码迷,mamicode.com
首页 > 其他好文 > 详细

HDU4336 Card Collector 概率DP求期望+状压

时间:2019-05-11 09:30:01      阅读:86      评论:0      收藏:0      [点我收藏+]

标签:pre   printf   define   一个   lin   概率   ring   size   pac   

题目大意:要集齐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;
}

HDU4336 Card Collector 概率DP求期望+状压

标签:pre   printf   define   一个   lin   概率   ring   size   pac   

原文地址:https://www.cnblogs.com/Bhllx/p/10847660.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!