合計数の組み合わせの数を見つける(コード内の変数n)。例:
3 = 1 + 1 + 1 = 2 + 1 = 3 => ANSは3
5 = 5 = 4 + 1 = 3 + 2 = 3 + 1 + 1 = 2 + 2 + 1 = 2 + 1 + 1 + 1 = 1 + 1 + 1 + 1 + 1 => ANSは7
次の例では、mが最大数で、n
が合計です。目的は、(合計)の組み合わせがいくつあるかを見つけることです。
なぜp(n, m) = p(n, m - 1) + p(n - m, m)
なのか知りたいだけですか?
ここのコード:
int p (int n, int m)
{
if (n == m)
return 1 + p(n, m - 1);
if (m == 0 || n < 0)
return 0;
if (n == 0 || m == 1)
return 1;
return p(n, m - 1) + p(n - m, m);
}
感謝!
n
以下の数値を追加して、m
を生成するすべての方法を検討してください。あなたが言ったように、私たちはこれをp(n,m)
と呼びます。たとえば、p(7,3)= 8は、以下に示すように3未満の数値から7を作成する8つの方法があるためです:(簡単にするために、常に大きいものから小さいものの順に数値を追加すると仮定できます)
これで、これらの組み合わせを2つのグループに分割できます。
最初の要素がm
(= 3この例では= 3)に等しい組み合わせ:)
最初の要素がm
未満の組み合わせ:
p(n,m)
の組み合わせのすべてのメンバーは、Group1またはGroup2のいずれかにあるため、p(n,m)=size(Group1) + size(Group2)
と言うことができます。ここで、置換によってsize(Group1)=p(n-m, m)
とsize(Group2)=p(n,m-1)
を証明すると、p(n,m)=p(n-m,m)+p(n,m-1)
に到達します。
size(Group1)=p(n-m, m)
を証明する:前述の定義によると、p(n-m, m)
は、m
以下の数値を追加することによって_n-m
_を生成する方法の数です。
p(n-m, m)
の各組み合わせにm
を追加すると、Group1のメンバーになります。だからp(n-m, m) <= size(Group1)
m
を削除すると、p(n-m, m)
の組み合わせになります。だからsize(Group1) <= p(n-m, m)
=> size(Group1) = p(n-m, m)
。この例では:
Group1 <===対応===> p(4、3):
3+1
_ <===========> _3+1
_ = 42+2
_ <===========> _2+2
_ = 42+1+1
_ <=======> _2+1+1
_ = 41+1+1+1
_ <===> _1+1+1+1
_ = 4したがって、p(n-m,m)
の任意のメンバーとGroup1の間には1対1の対応があり、それらのサイズは同じです。
size(Group2)=p(n, m-1)
を証明する:定義上、p(n,m-1)
は、_m-1
_(n
未満)以下の数値を追加してm
を生成する方法の数です。 Group2の定義を読み直すと、これら2つの定義が互いに同じであることがわかります。 => size(Group2) = p(n, m-1)
まず、この関数について知りたい以上のことについては、 http://mathworld.wolfram.com/PartitionFunctionP.html を参照してください。
この式に関しては、p(n, m)
は最大メンバーが最大でn
であるm
のパーティションの数として定義されていることに注意してください。
したがって、p(n, m)
は、最大メンバーが最大でm
であるm
のパーティションの数です。最大のメンバーが実際にm
であるかどうかに従ってそれらを分割しましょう。
最大メンバーがm
であるパーティションの数は、n = m + ...
を入力する方法の数です。これは、最大メンバーが最大でm
であるn-m
のパーティションの数であり、定義上p(n-m, m)
。
最大メンバーが最大でm-1
であるn
のパーティションの数は、定義上p(n, m-1)
です。
したがって、p(n, m) = p(n-m, m) + p(n, m-1)
。
/ 0 (k>n)
p(k,n)={ 1 (k=n)
\ p(k+1,n)+p(k,n-k) (k<n)
Nのパーティションの数はp(1、n)です。
p(k、n)はnのパーティションの数であり、加数> = kのみを許可します。
OPの再帰式のように、(luiges90が言っているように)それらを1つずつ追加します(多数のゼロの非効率性が追加されます)。ただし、幸いなことに、配列内で非常に高速に計算できます。
#include <stdio.h>
/* 406 is the largest n for which p(n) fits in 64 bits */
#define MAX 406
long long int pArray[MAX][MAX];
/* Emulate array starting at 1: */
#define p(k,n) pArray[k-1][n-1]
int main(int argc, char **argv) {
int n, k;
for (n = 1; n < MAX; n++) {
for (k = n; k > 0; k--) {
if (k > n) {
p(k, n) = 0;
}
else if (k == n) {
p(k, n) = 1;
}
else {
p(k, n) = p(k, n-k)+p(k+1, n);
}
}
}
for (n = 1; n < MAX; n++) {
printf("p(%d)=%lld\n", n, p(1,n));
}
}
合計がn
であり、各加数がm
以下であるすべての組み合わせの数として、p(n, m)
を示します。ここで重要な点は、次の再帰方程式を証明することです。
p(n, m) - p(n, m - 1) = p(n-m, m) (1)
(1)の左側は、p(n、m)とp(n、m --1)の差です。これらは、加数として少なくとも1つのm
を含むすべての組み合わせの数であり、残りは合計はn-m
(全体がn
になるように)、さらに各加数はm
以下です。しかし、それは正確には(1)の右側であるp(n-m、m)を意味します。
明らかに、質問の答えはp(n、n)でなければなりません。