【Luogu】P2473奖励关(期望DP)

  题目链接

  逆推期望DP。设f[i][j]为1~i-1中吃到的宝物集合为j,在i~k轮能得到的最大期望分数。

  如果不吃显然f[i][j]+=f[i+1][j]/n

  如果吃就是f[i][j]+=max(f[i+1][j]/n,(f[i+1][j|(1<<k-1)]+q[k])/n)

  然后照着这样的方程式搞一搞,最后答案就是f[1][0]。

  话说我一开始的状态设计就是题解吐槽的那种,然后我想了一个多小时发现:诶?转移不动呀?

  qwq

  

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define maxk 110
#define maxn 16
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

double f[maxk][1<<maxn];
int need[maxk][maxk],tot[maxk];
int q[maxk];
double ans;
int cnt;

int main(){
    int m=read(),n=read();
    for(int i=1;i<=n;++i){
        q[i]=read();
        int x=read();
        while(x){
            need[i][++tot[i]]=x;
            x=read();
        }
    }
    for(int i=m;i>0;--i)
        for(int j=0;j<(1<<n);++j){
            for(int k=1;k<=n;++k){
                int o=1<<(k-1);
                bool flag=0;
                for(int l=1;l<=tot[k];++l)
                    if(!(j&(1<<(need[k][l]-1)))){
                        flag=1;
                        break;
                    }
                if(flag)    f[i][j]+=f[i+1][j];
                else        f[i][j]+=max(f[i+1][j],f[i+1][j|o]+q[k]);
            }
            f[i][j]/=(double)n;
        }
    printf("%.6lf",f[1][0]);
    return 0;
}

 

posted @ 2018-01-06 13:45  Konoset  阅读(130)  评论(0编辑  收藏  举报