BZOJ 1076: [SCOI2008]奖励关 [DP 期望 状压]

传送门

题意:$n$种宝物,出现$k$次每次一种,每种宝物有价值和吃掉它之前必须要吃掉的宝物的集合,求采取最优策略的期望最大价值

1<=k<=100,1<=n<=15,分值为[-10^6,10^6]内的整数。


 

看到$n$应该想到状压....

$f[i][s]$表示前$i$次已经吃掉的集合为$s$的期望最大值

然而正推的话,答案是谁呢?

所以倒推,表示这个状态到结束得到的期望最大值

转移枚举出现的宝物,最后乘上概率$\frac{1}{n}$

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=105,S=1<<15;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int m,n,val[N],need[N];
double f[N][S];
int main(){
    freopen("in","r",stdin);
    m=read();n=read();
    for(int i=0;i<n;i++){
        val[i]=read();int x=read();
        while(x) need[i]|=(1<<(x-1)),x=read();
    }
    int All=1<<n;
    for(int i=m;i>=1;i--)
        for(int s=0;s<All;s++){
            for(int j=0;j<n;j++){
                if((s&need[j])==need[j]) f[i][s]+=max(f[i+1][s],f[i+1][s|(1<<j)]+val[j]); 
                else f[i][s]+=f[i+1][s];
            }
            f[i][s]/=n;
        }
    printf("%.6lf",f[1][0]);
}

 

posted @ 2017-03-05 16:26  Candy?  阅读(289)  评论(0编辑  收藏  举报