ZOJ 3777 Problem Arrangement ( 状压dp )

题目链接
在这里插入图片描述
大致题意:
输入 n n n m m m,接下来一个 n ∗ n n*n nn 的矩阵, m p [ i ] [ j ] mp[i][j] mp[i][j] 表示第 i i i 道题放在第 j j j 个顺序做可以加 m p [ i ] [ j ] mp[i][j] mp[i][j] 的分数,问做完 n n n 道题所得分数大于等于 m m m 的概率。用分数表示,分母为上述满足题意的方案数,分子是总的方案数,输出最简形式。

解题报告:
状压 d p dp dp,枚举所有 题目被选举的状态。
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示 i i i 状态下得分为 j j j 的方案总数

代码展示:

#include<bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define mem(a, b) memset(a,b,sizeof(a))
using namespace std;
const int maxn = 1e5 + 5;
const int MOD = 1e9 + 7;

int mp[15][15],n,m;
int dp[(1<<13)+5][505],fac[15];

int main() {
    ios::sync_with_stdio(NULL);cin.tie(NULL);cout.tie(NULL);
    fac[0]=1;
    for(int i=1;i<=12;i++) fac[i]=fac[i-1]*i;
    int T;
    cin>>T;
    while (T--) {
        mem(dp,0);
        cin>>n>>m;
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>mp[i][j];
        dp[0][0]=1;
        for(int i=0;i<(1<<n);i++){//枚举所有状态
            int cnt=0;
            for(int j=0;j<n;j++) if((i>>j)&1) cnt++;//该状态下有多少位置已被占有即前cnt道题目已被排列好
            for(int j=1;j<=n;j++){
                if((i>>(j-1))&1) continue;//被占有跳过
                for(int k=0;k<=m;k++){ //状态转移:当前状态可转移至其他哪些状态 例 010 -> 011或110
                    if(k+mp[cnt+1][j]>=m) dp[i+(1<<(j-1))][m]+=dp[i][k];//第cnt+1道题的放置
                    else dp[i+(1<<(j-1))][k+mp[cnt+1][j]]+=dp[i][k];
                }
            }
        }
        if(dp[(1<<n)-1][m]==0) cout<<"No solution"<<'\n';
        else{
            int gcd=__gcd(fac[n],dp[(1<<n)-1][m]);
            cout<<fac[n]/gcd<<"/"<<dp[(1<<n)-1][m]/gcd<<'\n';
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值