このプログラムは、n個の要素を持つセットのパーティション数をk個のサブセットにカウントするためのものです。ここで混乱していますreturn k*countP(n-1, k) + countP(n-1, k-1);
なぜkを掛けているのですか?
注->これは、DPになるパーティションの数を計算する最良の方法ではないことを知っています
// A C++ program to count number of partitions
// of a set with n elements into k subsets
#include<iostream>
using namespace std;
// Returns count of different partitions of n
// elements in k subsets
int countP(int n, int k)
{
// Base cases
if (n == 0 || k == 0 || k > n)
return 0;
if (k == 1 || k == n)
return 1;
// S(n+1, k) = k*S(n, k) + S(n, k-1)
return k*countP(n-1, k) + countP(n-1, k-1);
}
// Driver program
int main()
{
cout << countP(3, 2);
return 0;
}
countP
を呼び出すたびに、セット内の1つの要素が暗黙的に考慮され、それを呼び出すことができます[〜#〜] a [〜#〜]。
countP(n-1, k-1)
項は、[〜#〜] a [〜#〜]が単独でセットに含まれている場合に由来します。この場合、[〜#〜] a [〜#なので、他のすべての要素(N-1)を(K-1)サブセットに分割する方法がいくつあるかを数える必要があります。 〜]はそれ自体で1つのサブセットを使用します。
k*countP(n-1, k)
という用語は、[〜#〜] a [〜#〜]がである場合に由来しますそれ自体ではセットのnot。したがって、他のすべての(N-1)値をK個のサブセットに分割する方法の数を把握し、追加できるK個の可能なサブセットがあるため、Kを乗算します[〜#〜] a [ 〜#〜]に。
たとえば、セット_[A,B,C,D]
_と_K=2
_について考えてみます。
最初のケースcountP(n-1, k-1)
は、次の状況を示しています。
_{A, BCD}
_
2番目のケースk*countP(n-1, k)
は、以下のケースを示します。
_2*({BC,D}, {BD,C}, {B,CD})
_
または:
_{ABC,D}, {ABD,C}, {AB,CD}, {BC,AD}, {BD,AC}, {B,ACD}
_
あなたが言及したのは 第2種のスターリング数 で、n個のオブジェクトのセットをk個の空でないサブセットに分割して または 。
その再帰的な関係は次のとおりです。
ために k > 0
初期条件付き:
。
動的プログラミングを使用した計算は、再帰的アプローチよりも高速です。
int secondKindStirlingNumber(int n, int k) {
int sf[n + 1][n + 1];
for (int i = 0; i < k; i++) {
sf[i][i] = 1;
}
for (int i = 1; i < n + 1; i++) {
for (int j = 1; j < k + 1; j++) {
sf[i][j] = j * sf[i - 1][j] + sf[i - 1][j - 1];
}
}
return sf[n][k];
}
countP(n,k)
を取得するにはどうすればよいですか?以前の_n-1
_要素を特定の数のパーティションに分割し、現在はn番目の要素があり、k
パーティションを作成するとします。
これには2つのオプションがあります。
どちらか
n-1
_要素をk
部分に分割しました(これにはcountP(n-1, k)
の方法があります)。このn番目の要素をこれらの部分の1つに挿入します( k
の選択肢があります)。したがって、k*countP(n-1, k)
があります。または:
n-1
_要素を_k-1
_パーティションに分割します(これにはcountP(n-1, k-1);
の方法があります)。そして、n番目の要素をk
パーティション(選択肢は1つだけです:別に置く)。したがって、countP(n-1, k-1);
があります。したがって、それらを合計して結果を取得します。