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

Posted invictus-ocean

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

 

以上是关于SCOI2008奖励关 题解(状压DP+期望)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1076: [SCOI2008]奖励关(期望dp+状压dp)

BZOJ1076 [SCOI2008]奖励关

BZOJ1076[SCOI2008]奖励关 状压DP+期望

1076. [SCOI2008]奖励关状压DP+期望

[SCOI2008]奖励关 题解

[BZOJ 1076][SCOI2008]奖励关(期望+状压Dp)