• BZOJ1076 [SCOI2008]奖励关 概率 状态压缩动态规划


    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ1076


    题意概括

      有n个东西,k次扔出来。每次等概率扔出其中一个。

      你可以拿这个东西,但是有条件,得在拿到指定东西之后再拿,否则白拿。

      拿到一个东西,会获得其权值。可以是负数。


    题解

      状压dp跑一发。

      一开始想写正着dp的,因为我觉得这样听挺容易想的。

      然而网上的大牛都说是倒着的。于是我倒着了。

      方程是这样的:

      dp[i][j]表示扔出来i次之后,状态为j,在这之后可以得到的最大收益。

      dp[i][j]=(∑F[k])/n

      F[k]分两种情况。如果在状态j的情况下可以取k,那么F[k] = max(dp[i+1][j],dp[i+1][j | (1<<k)] + v[k])

        否则F[k] = dp[i+1][j]

      根据意义,最后输出dp[0][0]即可。


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=15+5,M=100+5,S=(1<<15)+5;
    int n,m,v[N],pre[N];
    double dp[M][S];
    int main(){
        scanf("%d%d",&m,&n);
        memset(pre,0,sizeof pre);
        for (int i=0,p;i<n;i++){
            scanf("%d",&v[i]);
            while (scanf("%d",&p)&&p!=0)
                pre[i]|=1<<(p-1);
        }
        for (int i=m-1;i>=0;i--)
            for (int j=0;j<(1<<n);j++){
                dp[i][j]=0;
                for (int k=0;k<n;k++)
                    if ((pre[k]&j)==pre[k])
                        dp[i][j]+=max(dp[i+1][j],dp[i+1][j|(1<<k)]+v[k]);
                    else
                        dp[i][j]+=dp[i+1][j];
                dp[i][j]/=n;
            }
        printf("%.6lf",dp[0][0]);
        return 0;
    }
  • 相关阅读:
    close 不弹出对话框
    ASP.NET会话(Session)保存模式
    ASP.NET页面刷新后滚动条保留在刷新前的位置 MaintainScrollPositionOnPostback
    CSS实现垂直居中的5种方法
    ExpandStackTrace
    HttpTunnel
    PropertyAccess类 Linq.Expressions 实现
    DatagramResolver
    AsyncUdpClient 类
    C# LockFreeStack类
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1076.html
Copyright © 2020-2023  润新知