ZOJ 3777 Problem Arrangement (状压DP)

分析:题目要求数学期望,其实就是求最终值 M 的概率。暴力的做法:找出所有排列方式,一个一个找: o(12!) ,贵了。对数据敏感的话,应该比较容易想到状压。
dp[i][msk][j] 代表前 i 个数用了msk状态的数,和为 j 的排列总数。
那么转移方程:

dp[i][msk][j]=mskk1dp[i1][msk|1<<k][jp[k][i]]

其实第一维根本没什么意义, msk 1 的个数就代表了i的值,所有可以把第第一维去掉:p

dp[msk][j]=mskk1dp[msk|1<<k][jp[k][cnt[msk]]]

代码:(由于角标是从 0 <script type="math/tex" id="MathJax-Element-2661">0</script>开始的,所以和上面的有点不太一样)

#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y)  for(int i = x;i < y;++ i)
#define IFOR(i,x,y) for(int i = x;i > y;-- i)

using namespace std;

typedef vector <int> VT;

const int maxn = 1<<12;
const int maxm = 550;

LL dp[maxn][maxm];

int p[12][12],cnt[maxn][13];

int n,m;

LL gcd(LL a,LL b){
    return b == 0 ? a : gcd(b,a%b);
}

int main()
{
    //freopen("test.in","r",stdin);
    FOR(i,0,maxn){
        cnt[i][0] = 0;
        FOR(j,0,12){
            if(i & (1<<j)){
                cnt[i][++cnt[i][0]] = j;
            }
        }
    }
    int T;  scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        FOR(i,0,n)
            FOR(j,0,n)  scanf("%d",&p[i][j]);
        dp[0][0] = 1;
        int MSK = 1<<n;
        FOR(i,0,m){
            FOR(msk,1,MSK){
                dp[msk][i] = 0;
                FOR(j,1,cnt[msk][0]+1){
                    int k = cnt[msk][j];
                    if(i < p[k][cnt[msk][0]-1])  continue;
                    dp[msk][i] += dp[msk^(1<<k)][i-p[k][cnt[msk][0]-1]];
                }
            }
        }
        LL sum = 1;
        FOR(i,1,n+1){
            sum *= i;
        }
        LL res = 0;
        FOR(i,0,m){
            res += dp[MSK-1][i];
        }
        res = sum - res;
        if(!res){
            printf("No solution\n");
            continue;
        }
        LL g = gcd(res,sum);
        res /= g;
        sum /= g;
        printf("%lld/%lld\n",sum,res);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值