[SCOI2008]奖励关

[Luogu2473]

原题解

结束状态很多 , 而初始状态是确定的 , 所以考虑从后往前\(DP\)或者从前往后记忆化搜索
转移可以参考[CH3803]扑克牌的记忆化搜索做法 , 而本题可以用\(DP\)

\(f[i][S]\)表示在第\(1\)轮到第\(i-1\)轮内宝物是否取过的状态为\(S\),第\(i\)轮到第\(K\)轮的最大期望得分
答案就是\(f[1][0]\)

状态的转移无非就是(轮数,已选状态)之间的递推 ; 还有就是一定要把题看清 , 比如这里的每个物品只能得一次分

如果可以取 , \(f[i][S]+=max(f[i+1][S],f[i+1][S|(1<<k-1)]+P_k)\)
否则不能取 , 即\(f[i][S]+=f[i+1][S]\)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int MAXN=17;
const int MAXM=105;

double f[MAXM][1<<15],ans;
int p[MAXN],sta[MAXN],n,m,x;

int main(){
    m=read(),n=read();
    for(int i=1;i<=n;i++){
        p[i]=read();
        while(x=read()) sta[i]|=1<<(x-1);
    }
    for(int i=m;i>=1;i--)
    for(int j=0;j<(1<<n);j++){
        for(int k=1;k<=n;k++){
            if((j&sta[k])==sta[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;//求的是期望,所以还要/n
    }
    printf("%.6lf\n",f[1][0]);
}

转载于:https://www.cnblogs.com/lizehon/p/10570754.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值