The 11th Zhejiang Provincial Collegiate Programming Contest is coming! As a problem setter, Edward is going to arrange the order of the problems. As we know, the arrangement will have a great effect on the result of the contest. For example, it will take more time to finish the first problem if the easiest problem hides in the middle of the problem list.
There are N problems in the contest. Certainly, it's not interesting if the problems are sorted in the order of increasing difficulty. Edward decides to arrange the problems in a different way. After a careful study, he found out that the i-th problem placed in the j-th position will add Pij points of "interesting value" to the contest.
Edward wrote a program which can generate a random permutation of the problems. If the total interesting value of a permutation is larger than or equal to M points, the permutation is acceptable. Edward wants to know the expected times of generation needed to obtain the first acceptable permutation.
Input
There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:
The first line contains two integers N (1 <= N <= 12) and M (1 <= M <= 500).
The next N lines, each line contains N integers. The j-th integer in the i-th line is Pij (0 <= Pij <= 100).
Output
For each test case, output the expected times in the form of irreducible fraction. An irreducible fraction is a fraction in which the numerator and denominator are positive integers and have no other common divisors than 1. If it is impossible to get an acceptable permutation, output "No solution" instead.
Sample Input
2 3 10 2 4 1 3 2 2 4 5 3 2 6 1 3 2 4
Sample Output
3/1 No solution
题意:给出n道题目以及每一道题目不同时间做的兴趣值,让你求出所有做题顺序中兴趣值不小于m的比例。按一个分数表示。
思路转自:http://blog.csdn.net/y990041769/article/details/24136457
分析:首先想到的肯定是深搜,深搜枚举一个全排列,然后同时求和,看和大于等于m有多少种,输出结果,但是n的范围是(0--12)12!不能满足深搜的时间限
制,所以在比赛的时候华丽的超时了。
后面,想到了用dp来做,用dp【i】【j】来表示做了 i 道题目的趣味值为 j 的个数。那么可以用dp【i】【k+a【x】【i】】+=dp【i-1】【k】;但是发现其中的 x 是一个
不好控制的量,x表示从之前没有取过的行里面的所有行,但是怎么表示一个行有没有取过呢。。。是一个难题!!!想到用vector,但是发现它每次还是转移的,那
么我们是不是可以转移呢,但是发现转移后他有可能不只表示一种的,卡到这儿写不下去。
其实是个状态压缩dp,状态压缩就是把一些状态较少的情况用二进制的1表示出现0表示没有出现来表示,这样不仅表示方便快速,转移也方便
前面不能表示的状态我们可以用一个状态压缩dp来表示,///dp[i][j]表示取i的二进制位为1的值兴趣值为j时的个数
那么我们就可以转移了。dp[i+(1<<(j-1))][k+a[tmp+1][j]] += dp[i][k];
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn = 1 << 13;
int dp[maxn][505], t, a[15][15], m, n;
int main()
{
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%d", &a[i][j]);
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(int i = 0; i < (1<<n); i++)
{
int cnt = 0;
for(int j=1;j <= n;j++)
if(i&(1<<(j-1)))
cnt++; //代表放了几行几列
for(int j = 1; j <= n; j++)
{
if(i & (1<<(j-1))) continue; //已经放过的就不必放了
for(int k = 0; k <= m; k++) //这里是精髓。。。
{
if(k+a[cnt+1][j] >= m) //大于m 就让他是m
dp[i|(1<<(j-1))][m] += dp[i][k];
else
dp[i|(1<<(j-1))][k+a[cnt+1][j]] += dp[i][k]; //这样转移。。
}
}
}
int ans = dp[(1<<n)-1][m];
if(!ans)
printf("No solution\n");
else
{
int fact = 1;
for(int i = 1; i <= n; i++)
fact *= i;
int gcd = __gcd(fact, ans);
printf("%d/%d\n", fact/gcd, ans/gcd);
}
}
return 0;
}