zoukankan      html  css  js  c++  java
  • 2014 Super Training #4 B Problem Arrangement --状压DP

    原题:ZOJ 3777  http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3777

    题意:给每个题目安排在每个位置的value。有一个程序随机选择安排的顺序,总的value值大于等于m时,就可以接受这个安排。问能够获得一次满足条件的安排的期望次数。

    这题不会做,看网上是用状态压缩DP做的。

    定义: dp[i][j]为选取了前i行,趣味和为j的方案种数。

    由于程序是每次随机选择一个排列,每次的选择之间不影响,而且每次选中的概率相等,都为dp[S][m]/ fac[n] , 即满足条件的总数/ 总排列数。由于01分布的期望为p , 这里p = dp[S][m]/ fac[n],p为试验一次事件发生的概率,那么,事件一定发生试验的次数为1/p 。 所以结果为  fac[n]/dp[S][m] ,结果用最简形式表示。(S = (1<<n)-1). (参考玻璃年华Alex

    方程:dp[i|(1<<j)][k+a[R][j]] += dp[i][k];   

     i 即一个01串,其中1的个数表示已经选择的行数,用R表示,则下一次要选第R+1行的数(由于下标从0开始,所以仍是a[R][j]),1的位置表示选取的前i行中选取的数的列的情况,下一次选的时候就不能选这些列了。 然后转移,如果k + a[R][j] > m,则令其为m即可,因为大于m后值就没有意义了。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 14
    
    int fac[N],a[N][N];
    int dp[5007][510];
    
    void INIT_FAC()
    {
        fac[1] = 1;
        for(int i=2;i<=12;i++)
            fac[i] = fac[i-1]*i;
    }
    
    int gcd(int a,int b)
    {
        if(!b)
            return a;
        return gcd(b,a%b);
    }
    
    int main()
    {
        int t,n,m,i,j,k,R;
        INIT_FAC();
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            for(i=0;i<n;i++)
                for(j=0;j<n;j++)
                    scanf("%d",&a[i][j]);
            memset(dp,0,sizeof(dp));
            dp[0][0] = 1;
            int S = (1<<n)-1;
            for(i=0;i<=S;i++)
            {
                R = 0;
                for(j=0;j<n;j++)
                    if(i & (1<<j))
                        R++;
                //已访问R行
                for(j=0;j<n;j++) //放置第R+1行(下标仍为R),枚举其放置的列
                {
                    if(i & (1<<j)) //这列已用过
                        continue;
                    for(k=0;k<=m;k++)  //枚举和
                        dp[i|(1<<j)][min(k+a[R][j],m)] += dp[i][k];  //和超过m算作m
                }
            }
            if(dp[S][m])
            {
                int g = gcd(fac[n],dp[S][m]);
                printf("%d/%d
    ",fac[n]/g,dp[S][m]/g);
            }
            else
                puts("No solution");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    对象属性对话框只能放大不能缩小
    Windows2003 Server升级至SP2后,水晶报表导出EXCEL出错
    磁盘结构损坏且无法读取
    InsusCharacterUtility.dll怎么调用
    会员综合实例
    无法连接SQL Server 2008
    JavaScript alert Utility
    DNS与Active Directory在两台服务器分别布署
    显示用户权限
    焦点新闻图片轮翻广告
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3819092.html
Copyright © 2011-2022 走看看