1.斯特林数
斯特林数(第二类)的解法是用于计算将一个集合划分为若干个非空子集的方法数。对于题目描述中的问题,即如何将集合 {1, 2, ..., n}
划分为若干个非空子集,我们使用斯特林数的思想来解决。
一、斯特林数(第二类)简介
斯特林数(第二类)表示将一个包含 nnn 个元素的集合划分成 kkk 个非空子集的数量,记作 S(n,k)S(n, k)S(n,k)。
斯特林数的特点:
- 每个子集都必须非空。
- S(n,k) 表示将 n 个元素划分为 k 个非空子集的方式数。
例如,当 n=3n = 3n=3,我们可以将集合 {1, 2, 3}
划分为以下几种情况:
- 1 个子集:{{1, 2, 3}}
- 2 个子集:{{1}, {2, 3}}, {{2}, {1, 3}}, {{3}, {1, 2}}
- 3 个子集:{{1}, {2}, {3}}
二、递推公式
三、总划分数的计算
#include <iostream>
#include<vector>
using namespace std;
const int MAX = 18;
//初始化斯特林数的动态规划表
long long S[MAX + 1][MAX + 1] = { 0 };
//由于题目中的18是一个较小的数字,且要对n进行反复的查看,因此存储每个n的斯特林数的值
long long partitions[MAX + 1] = { 0 };
void precompute_strling() {
//初始化
S[0][0] = 1;
//动态计算斯特林数
for (int n = 1; n <= MAX; n++){
for (int k = 1; k <= n; k++) {
S[n][k] = S[n - 1][k - 1] + k * S[n - 1][k];
}
}
//存储
for (int n = 1; n <= MAX; n++) {
for (int k = 1; k <= n; k++) {
partitions[n] += S[n][k];
}
}
}
int main() {
int n;
precompute_strling();
while (cin >> n) {
cout << partitions[n] << endl;
}
return 0;
}