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

题目链接

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

$n\leq 15,-10^6\leq p_i\leq 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;
}

 

posted @ 2020-07-12 12:51  我亦如此向往  阅读(127)  评论(0编辑  收藏  举报