设S是一个具有n个元素的集合,S={a1,a2,……,an},现将S划分成k个满足下列条件的子集合S1,S2,……,Sk ,且满足:
则称S1,S2,……,Sk是集合S的一个划分。它相当于把S集合中的n个元素a1 ,a2,……,an 放入k个(0<k≤n<30)无标号的盒子中,使得没有一个盒子为空。请你确定n个元素a1 ,a2 ,……,an 放入k个无标号盒子中去的划分数S(n,k)。
输入:输入集合的元素个数n和划分的个数k
输出 :输出划分数
样例输入:
23 7
样例输出:
4382641999117305
思路:虽然我也不是特别通透这题,但是自我感觉这个题把所有元素的状态累加叠起来了,一层一层的叠出结果,首先我们不把所有元素一起看,先看其中一个元素,由于是集合所以里面的所有元素都是不一样的,随便选一个就好,(这句话如果难以理解可以暂时忽略,下面是重点),对于这个元素它绝对!绝对!只有两种情况!
情况一:
它所在的集合只有它这一个元素,那么我们就可以把这个元素和这个集合都删掉,这个情况下的划分数是和S(n-1,k-1)相等的,就是在S(n-1,k-1)的情况下再加上一个只有它一个元素的集合。
情况二:
它所在的集合不只它一个元素,那么我们就不能把这个集合删去,因为这个集合里还有别的元素,那么我们先删去这个元素,求S(n-1,k),然后把这个元素在每一个容器里都放一遍,放k遍,都会产生不同的结果,那么这个情况下的划分数就是S(n-1,k)*k;
把这两种情况相加我们就可以得出S(n,k)的总值,这个用递归是可以解决的,那么现在要注意边界调节,n=k的时候是只有一种情况的,就是每个容器里都放一个元素,k=1的时候情况也只有一种,把所有元素都放在这个容器里,如果递归到这种情况返回一,如果会造成有容器是空的情况,那么这种情况是不可能,因为不符合题目条件。遇到这种情况要返回0。考虑到这些我们就可以写程序了
代码:
#include<stdio.h>
typedef long long LL;
LL dfs(int n,int k)
{
if(n==0)
return 0;
if(k>n)
return 0;
if(k==1 || n==k)
return 1;
else
return k*dfs(n-1,k)+dfs(n-1,k-1);
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
printf("%lld\n",dfs(n,k));
return 0;
}
样例可以自己举试试看