集合的划分(状态的叠加)

来源:互联网 发布:新东方英语网络教学 编辑:程序博客网 时间:2024/05/18 02:28
题目:

S是一个具有n个元素的集合,S={a1a2……an},现将S划分成k个满足下列条件的子集合S1S2……Sk ,且满足:

 

则称S1S2……Sk是集合S的一个划分。它相当于把S集合中的n个元素a1 a2……an 放入k个(0k≤n30)无标号的盒子中,使得没有一个盒子为空。请你确定n个元素a1 a2 ……an 放入k个无标号盒子中去的划分数S(nk)

输入:输入集合的元素个数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;}
样例可以自己举试试看

原创粉丝点击