今天上课做到了集合划分的问题,其实是一个比较基础的递归
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 },{3,2 }}; {{2,3,4},{1}}; {{1,3,4},{2}};
{{1,2, 4},{3}}; {{1,2,3},{4}}; {{1,2,3,4}};
给定正整数N,计算出N个元素的集合{1,2,…,N}可以划分多少个非空集合?
那么其实,本道题目最重要的就是找到其中的递归关系。首先其用更加具体的例子就是将n个球放到不限数量的盒子中一共有多少种算法。那么可以将问题分解为将n个球放到1个盒子中、放到2个盒子种、三个.......n个盒子中。其中用k来表示盒子的数量。当k==n或者k==1或者n==1的时候都只有一种情况,这样就找到了递归的边界值。那么当把n个球放到k个盒子之中时,可以将第n个球单独拿出分析。第一种情况是第n个球单独一个盒子,那么这种情况的可分个数就是将n-1个球放到k-1个盒子之中的个数。第二种情况就是将第n个球不单独放到一个盒子里去,也就是说,现有n-1个球放到k个盒子中的情况,然后把这个球放到k个盒子中的任意一个,也就是这种情况下共有k*f(n-1,k)个方法,因此得到递归方式和边界值,接下来进行递归就好了。
#include<iostream>
using namespace std;
int f(int n,int k)
{
if(k==1 or n==k or n==1) return 1;
if(k==0 or n<k or n==0) return 0;
return f(n-1,k-1)+k*f(n-1,k);
}
int main()
{
int n = 4;
int num=0;
for(int i = 1;i<=n;i++)
{
num+=f(n,i);
cout<<n<<"个数字分为"<<i<<"个集合一共有"<<f(n,i)<<"种情况"<<endl;
}
cout<<n<<"的集合划分个数一共有"<<num<<"种情况"<<endl;
}