您的位置:首页 > 其它

hdu 湫秋系列故事——安排座位(组合dp)

2013-07-22 16:29 225 查看
/*

 * 以前比赛的时候做这题,一点思路都没有,后面就放了放;

 * 

 * 今天突然想来弄下这题,于是去拜访了大牛的博客,了解到了组合dp的解法

 * 

 * 解法如下: 首先我们令F[i][j]表示前i个系的所有学生坐在座位上,出现了j对相邻学生是同一个系的

 * 

 * 那么对于接下来一个系的a个学生,我们可以把这个系的学生插入前面出现的j对相邻学生的中间,从而使他们变得不相邻

 * 

 * 现在的问题在于怎么去插入,我们可以采用分组的方法,我们把这个系的a个学生分成k组,从k组中选g组插入前面的j对相邻的

 * 

 * 学生中间,其他的组插入其他的空格内,则插入的方案数为A(a,a)*C(j,g)*C(sum+1-j,k-g)*C(a-1,k-1)(sum为前i个系的总的学生,

 * 

 * A(a,a)表示学生的位置全排,C(j,g)表示j个空插入g组,C(sum-1-j,k-g)表示剩下的空插入剩下的组,C(a-1,k-1)表示用隔板法把a个学生分成k组)

 * 

 * 因此转移方程为F[i][j-g+a-k]+=F[i-1][j]*A(a,a)*C(j,g)*C(sum+1-j,k-g)*C(a-1,k-1)且F[0][0]=1;

 * 

 *
 */

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

#define mod 1000000007

long long F[50][500],C[510][510],A[55];
long long dfs(int n,int m)
{
if(n<m) return 0;
if(m==0||n==m) return 1;
if(C
[m]!=-1) return C
[m];
return C
[m]=(dfs(n-1,m-1)+dfs(n-1,m))%mod;
}
int main(){
int cas,n,k,i,g,j,a,sum,t=1;
memset(C,-1,sizeof(C));A[0]=1;
for(i=1;i<=50;i++) A[i]=(A[i-1]*i)%mod;
for(i=0;i<=500;i++) for(j=0;j<=500;j++) C[i][j]=dfs(i,j);
scanf("%d",&cas);
while(cas--){
scanf("%d",&n);
memset(F,0,sizeof(F));
F[0][0]=1;sum=0;
for(i=1;i<=n;i++){
scanf("%d",&a);
for(j=0;j<=sum;j++){
for(k=1;k<=a;k++){
for(g=0;g<=j&&g<=k;g++){
F[i][j-g+a-k]+=(((F[i-1][j]*C[a-1][k-1])%mod*C[j][g])%mod*C[sum+1-j][k-g])%mod*A[a]%mod;
F[i][j-g+a-k]%=mod;
}
}
}
sum+=a;
}
printf("Case %d: %d\n",t++,int(F
[0]));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: