您的位置:首页 > 大数据 > 人工智能

2014 Super Training #4 B Problem Arrangement --状压DP

2014-07-01 21:35 295 查看
原题:ZOJ 3777 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3777

题意:给每个题目安排在每个位置的value。有一个程序随机选择安排的顺序,总的value值大于等于m时,就可以接受这个安排。问能够获得一次满足条件的安排的期望次数。

这题不会做,看网上是用状态压缩DP做的。

定义: dp[i][j]为选取了前i行,趣味和为j的方案种数。

由于程序是每次随机选择一个排列,每次的选择之间不影响,而且每次选中的概率相等,都为dp[S][m]/ fac
, 即满足条件的总数/ 总排列数。由于01分布的期望为p , 这里p = dp[S][m]/ fac
,p为试验一次事件发生的概率,那么,事件一定发生试验的次数为1/p 。 所以结果为 fac
/dp[S][m] ,结果用最简形式表示。(S = (1<<n)-1). (参考玻璃年华Alex

方程:dp[i|(1<<j)][k+a[R][j]] += dp[i][k];

i 即一个01串,其中1的个数表示已经选择的行数,用R表示,则下一次要选第R+1行的数(由于下标从0开始,所以仍是a[R][j]),1的位置表示选取的前i行中选取的数的列的情况,下一次选的时候就不能选这些列了。 然后转移,如果k + a[R][j] > m,则令其为m即可,因为大于m后值就没有意义了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 14

int fac
,a

;
int dp[5007][510];

void INIT_FAC()
{
fac[1] = 1;
for(int i=2;i<=12;i++)
fac[i] = fac[i-1]*i;
}

int gcd(int a,int b)
{
if(!b)
return a;
return gcd(b,a%b);
}

int main()
{
int t,n,m,i,j,k,R;
INIT_FAC();
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&a[i][j]);
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
int S = (1<<n)-1;
for(i=0;i<=S;i++)
{
R = 0;
for(j=0;j<n;j++)
if(i & (1<<j))
R++;
//已访问R行
for(j=0;j<n;j++) //放置第R+1行(下标仍为R),枚举其放置的列
{
if(i & (1<<j)) //这列已用过
continue;
for(k=0;k<=m;k++)  //枚举和
dp[i|(1<<j)][min(k+a[R][j],m)] += dp[i][k];  //和超过m算作m
}
}
if(dp[S][m])
{
int g = gcd(fac
,dp[S][m]);
printf("%d/%d\n",fac
/g,dp[S][m]/g);
}
else
puts("No solution");
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: