集合的划分

集合的划分(1)

【问题描述】
设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)。
【输入样例】setsub.in
23 7
【输出样例】setsub.out
4382641999117305
【分析】本题首先想到用dp求解,状态S(n,k)题中已经设定好了,那么关键在于如何转移我们的状态;
(搜索貌似过不了,也不会写QAQ)
对于一个二维的状态dp[i][j],一般必须从i,j的先前状态转移,不能只转移一维,那么就需要进行分类
(1){an}单独放在一个盒子里面,只需要将dp[i-1][j-1]的情况求出(即i-1个球放在j-1个盒子里面)
(2)an放在其他的盒子里面,则先把a1~an-1放到j个盒子里,an再放进这j个盒子中,有j种方法。即dp[i-1][j]*j
根据加法原理,dp[i][j]=dp[i-1][j-1]+dp[i-1][j]*j;
别忘了初始化,当k=1时 ,dp[i][1]=1;
代码如下:
#include<bits/stdc++.h>
using namespace std;
int n,k;
int dp[35][35];
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        dp[i][1]=1,dp[i][i]=1;
    for(int i=1;i<=n;i++)
        for(int j=2;j<=i;j++)
        {
            dp[i][j]=dp[i-1][j-1]+j*dp[i-1][j];
            //i球j盒 
        }
    printf("%d",dp[n][k]);
    return 0;
}

 

 
posted @ 2021-01-21 08:18  conprour  阅读(616)  评论(0编辑  收藏  举报