您的位置:首页 > 其它

ZOJ 3777 Problem Arrangement-状压dp

2016-04-11 14:13 363 查看
http://www.icpc.moe/onlinejudge/showProblem.do?problemCode=3777

输入n,m;

给一个n*n的矩阵,mp[i][j]表示第i题选题目j会有 相应的得分

让你选择一个序列,求序列得分超过m的个数

n《12,m<=500

可以把12种状态压位到一个int

dp[i][j] 中的i有cnt个1,表示选了前cnt题,那么接下来选的是cnt+1题,

for一遍 (j=1;j<=n;j++)

如果 (1<<(j-1))&i =1表示题被选过了,不能再选

如果可以选的话,那么 dp【i+1<<(j-1)】【cur_val+ mp[ cnt+1][j] 】+= dp【i】【cur_val】;

当然为了节省空间,当cur_val+ mp[ cnt+1][j]》m,我们令其等于M即可。。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;

const double pi=acos(-1.0);
double eps=0.000001;
int min(int a,int b)
{return a<b?a:b;}
int max(int a,int b)
{return a>b?a:b;}

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

int n,m;
int my_popcount(int x)
{
int tmp=0;
for(int j=1;j<=n;j++)
if(x&(1<<(j-1)))
tmp++;
return tmp;
}
int jie[15];
int mp[25][25];
int dp[1<<12][505];
int main()
{

jie[1]=1;
for(int i=2;i<13;i++)
jie[i]=jie[i-1]*i;
int t;cin>>t;
while(t--)
{
int i,j,k;
cin>>n>>m;
memset(dp,0,sizeof dp);

for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
scanf("%d",&mp[i][j]);
dp[0][0]=1;
int all=1<<n;
for (i=0;i<all;i++)		//状态
{
int cnt = my_popcount(i);
for (j=1;j<=n;j++)	//选第j题
{
if (i&(1<<(j-1) ) ) continue;
for (k=0;k<=m;k++)		//价值
{
if (dp[i][k]==0)continue;
dp[i+(1<<(j-1))][ min(k+ mp[cnt+1][j],m) ] += dp[i][k];
}
}
}
if (!dp[(1<<n)-1][m])
printf("No solution\n");
else
{
int gd=gcd(jie
,dp[(1<<n)-1][m]);
printf("%d/%d\n",jie
/gd,dp[(1<<n)-1][m]/gd);

}

}

return 0;

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