ZOJ 3777Problem Arrangement-状压dp

来源:互联网 发布:一直提示安装java 编辑:程序博客网 时间:2024/06/08 06:37

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[n],dp[(1<<n)-1][m]);printf("%d/%d\n",jie[n]/gd,dp[(1<<n)-1][m]/gd);}}return 0;}




0 0