【2-7】集合划分问题

问题描述:
n 个元素的集合{1,2,, n }可以划分为若干个非空子集。例如,当 n=4 时,集合{1,2,
3,4}可以划分为 15 个不同的非空子集如下:
{{1},{2},{3},{4}},
{{1,2},{3},{4}},
{{1,3},{2},{4}},
{{1,4},{2},{3}},
{{2,3},{1},{4}},
{{2,4},{1},{3}},
{{3,4},{1},{2}},
{{1,2},{3,4}},
{{1,3},{2,4}},
{{1,4},{2,3}},
{{1,2,3},{4}},
{{1,2,4},{3}},
{{1,3,4},{2}},
{{2,3,4},{1}},
{{1,2,3,4}}
´编程任务:
给定正整数 n,计算出 n 个元素的集合{1,2,, n }可以划分为多少个不同的非空子集。
´数据输入:
由文件 input.txt 提供输入数据。文件的第 1 行是元素个数 n。
´结果输出:
程序运行结束时,将计算出的不同的非空子集数输出到文件 output.txt 中。
输入文件示例 输出文件示例
input.txt output.txt
5 52

【题解】

Bell数的第i项就对应了1..i的非空集合划分个数。 可以这样递推 b[0]=b[1]=1(空或只有一个元素的话,那么只有一个划分,就是都把它们本身放在一个集合里) 否则 ```cpp for (int i = 2;i <= N;i++){ ll temp = 0; for (int j = 0;j < i;j++){ temp = temp + C(i-1,j)*bell[j];//在前i-1个数中挑出j个,它们和i不在一个集合中,其余的(i-1-j)个数都和i在同一个集合中. } bell[i] = temp; } ```

【代码】

#include <cstdio>
#define ll long long
using namespace std;

const int N = 18;

int n;
ll f[N+10];
ll bell[N+10];

ll C(int n,int m){
    if (n<m) return 0;
    /*
        n!/(n-m)!*m!
    */
    ll temp1 = f[n]/f[n-m];
    ll temp2 = f[m];
   // printf("C(%d,%d)=%I64d
",n,m,temp1/temp2);
    return temp1/temp2;
}

int main(){
    f[0] = 1;
    for (int i = 1;i <= N;i++) f[i] = 1LL*f[i-1]*i;
    bell[0] = 1;bell[1] = 1;
    for (int i = 2;i <= N;i++){
        ll temp = 0;
        for (int j = 0;j < i;j++){
            temp = temp + C(i-1,j)*bell[j];
        }
        bell[i] = temp;
    }
    int n;
    scanf("%d",&n);
    printf("%I64d
",bell[n]);
    return 0;
}

原文地址:https://www.cnblogs.com/AWCXV/p/11636381.html