HDU4336 Card Collector DP求期望+状压

题目大意:要集齐N张卡片,每包干脆面出现每种卡片的概率已知,问你集齐N张卡片所需要的方便面包数的数学期望(N<=20)。

solution:

由于N<=20,我们可以考虑状压,设dp[S]表示牌的状态为S时的需要的方便面包数的数学期望。

那么,对于每一个状态,考虑枚举每一张牌i(摸到了i),此时:

① 如果S中不含i,dp[S]+=(dp[S|(1<<i-1)]+1)*p[i]。

② 如果S中已经包含i,那么算到下面的情况中去。

但是注意到,上述情况是已经保证了摸到牌,但是其实可以没有摸到牌,结合②则dp[S]=(dp[S]+1)*P,其中P为摸不到任意一张牌或摸到一张已有的牌的概率,可以发现\(P+\sum{①中的p_i}=1\)

综上,得到\(dp[S]=(dp[S]+1) *P+\sum{_{!(S\&(1<<i-1))}(dp[S|(1<<i-1)]+1) *p[i]}​\)

把式子整理一下,得到: \(dp[s]=\frac{1+\sum{_{!(S\&(1<<i-1)}}dp[S|(1<<i-1)*p[i]]}{1-P}\)

Code:

#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;

const int N=1<<21;

DB p0,p[21],dp[N];

int main()
{
    RG int n,i,j,all;
    while(scanf("%d",&n)!=EOF) {
        all=(1<<n)-1;
        memset(dp,0,sizeof(dp));
        for(i=1;i<=n;++i) scanf("%lf",&p[i]);
        for(i=all-1;i>=0;--i) {
            for(j=1,p0=0;j<=n;++j)
                if(!(i&(1<<j-1))) dp[i]+=dp[i|(1<<j-1)]*p[j],p0+=p[j];
            dp[i]=(dp[i]+1)/p0;
        }
        printf("%.4lf\n",dp[0]);
    }
    return 0;
}

转载于:https://www.cnblogs.com/Bhllx/p/10847660.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值