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;
}