集合的划分(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
【输入样例】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; }