★ZOJ 3777 Problem Arrangement 详解(壮压DP)

6 篇文章 3 订阅


Problem Arrangement

Time Limit: 2 Seconds       Memory Limit: 65536 KB

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


下面壮压枚举的是前i行 列的方案。。。 s里面有几个1 代表放了几列,有j列也说明有j行啊。。。然后就是枚举m(壮压做的少,第一次见。。)应该是类似背包那种吧。。。
dp【i】【j】来表示做了 i 道题目的趣味值为 j 的个数,这种方式经常有的。。。

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



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值