0
0

More than 1 year has passed since last update.

【Project Euler】Problem 76: 整数の分割

Posted at

  • 本記事はProjectEulerの「100番以下の問題の説明は記載可能」という規定に基づいて回答のヒントが書かれていますので、自分である程度考えてみてから読まれることをお勧めします。

問題 76. 整数の分割

原文 Problem 76: Counting summations

問題の要約:100を自然数の和で何通りの組み合わせで表せるかを求めよ

分割数の漸化式

これは有名な「自然数の分割(Wikipedia)」の問題ですね。たぶんこれだけで本が書けるくらい多くの話題がありそうですが、こちらの「分割数の意味と性質・ヤング図形の活躍」が割と簡潔にまとまっているかなと思います。ここで以下の漸化式が出ています。

p_k(n)=p_k(n−k)+p_{k−1}(n−1)

再帰関数での実装

これをもとにして書いたのがこちら、再帰関数で繰り返しが多いのでlru_cacheを使っています。

from functools import lru_cache
@lru_cache(maxsize=None)
def npart(n, k):
  if n == 0 or k==1: return 1
  ret = npart(n, k-1)
  if n >= k:
    ret += npart(n-k, k)
  return ret
n = 100
print("Answer: {npart(n,n)-1}") 

配列を使った実装

再帰関数を使わずに配列を使って実装したのがこちら。かなりシンプルになってます。

def npart(n):
  p = [1]+[0]*n
  for i in range(1, n+1):
    for j in range(i, n+1):
      p[j] += p[j-i]
  return p[n]

print(f"Answer: {npart(100)-1}")

sympyの関数(partitions, npartitions)

これだけ有名な問題なのでさすがにsympyにありますね。まずは分割の数をすべてリストしてくれるpartitions

from sympy.utilities.iterables import partitions
n = 4
print(list(partitions(n)))
# [{4: 1}, {3: 1, 1: 1}, {2: 2}, {2: 1, 1: 2}, {1: 4}]

そしてまさに分割数を返す関数npartitions。あっけなく答えが求まります。

from sympy.ntheory import npartitions
print(f"Answer: {npartitions(100)-1}")

(開発環境:Google Colab)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0