• 【SCOI2008】奖励关 题解(状压DP+期望)


    题目链接

    题目大意:给定$n$个宝物,每次随机抛出一个宝物,奖励分数为$p_i$。但如果选这个宝物必须选过它的前置宝物集合。共进行$K$轮问最优策略下的期望。

    $nleq 15,-10^6leq p_ileq 10^6$

    --------------------------

    看到数据范围,状压很容易想到。

    设$f[i][j]$表示到了第$i$轮,宝物取舍状态为$j$的最大期望得分。

    但这样表示有一个问题:可能在第$i$轮没法到达状态$j$。我们无法预知未来。

    改一下定义:$f[i][j]$表示第$1$轮到第$i-1$轮宝物取舍状态为$j$,第$i$轮到第$K$轮的最大期望得分。有如下状态转移方程:

    如果前置宝物都已经取过,那么有$f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<(k-1))]+p[k])$

    如果没有,则直接继承先前状态:$f[i][j]+=f[i+1][j]$。

    最后再除$n$即为期望值。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,K,p[16],s[16],x;
    double f[105][1<<16];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int main()
    {
        K=read(),n=read();
        for (int i=1;i<=n;i++)
        {
            p[i]=read();
            while(x=read()) s[i]=s[i]|(1<<x-1); 
        }
        for (int i=K;i>=1;i--)
            for (int j=0;j<(1<<n);j++)
            {
                for (int k=1;k<=n;k++)
                    if ((j&s[k])==s[k]) f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<k-1)]+p[k]);
                    else f[i][j]+=f[i+1][j];
                f[i][j]/=n; 
            }
        printf("%lf",f[1][0]);
        return 0;
    }
  • 相关阅读:
    我的WCF之旅(1):创建一个简单的WCF程序
    c#自定义类型的转换方式operator,以及implicit(隐式)和explicit (显示)声明的区别
    Linux 系统时间设置
    Redis入门
    线程安全的单例模式
    redis-Sentinel配置
    openpose
    Qt5.11参考文档
    opencv3.3
    opencv3.4 win10 visual studio2017 opencv_contrib 编译
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13288024.html
Copyright © 2020-2023  润新知