hdu 4336 概率DP 状压DP

/*
    概率DP  状压DP  条件期望DP  好题


    题意:有n种卡片,一袋面里有一张卡片或者没有。给出每种卡片出现在一袋面里的概率,问要收集完n种卡片所需要买的袋面数目的期望(n <= 20).


    思路:状压表当前已收集到的卡片的状态,位为1表收集到了,0表没有收集到。
          对于状态T,考虑最近买的那袋面之前的状态S(也就是状态X在买了这袋面之后变成了状态T),
            <1>这袋面没有卡片
            <2>这袋面的卡片X已经收集过了
            <3>这袋面的卡片X还没有收集过
    方法1: 
          前两种情况新旧状态不变,即T = S;后面一种情况S = T ^ (1<<k)
          则T数学期望E(T) = 1 + (1 - Σp[i])*E(T) + Σ(p[j]*E(T)) + Σ(p[k]*E(S))
          其中:i = 0, 1, 2,...n-1
                j = 第j种卡片已经收集过了,S & (1<<j) == 1
                k = 第k种卡片还没有收集过,S & (1<<j) == 0
               
          移项可得:E(T) * Σp[k] = 1 + Σ(p[k] * E(S)    ,这里的k=第k种卡片没收集到,S = T ^ (1<<k)


          ps:我之前一直很奇怪为什么大家的代码没有对“袋面里可能没有卡片”这一点做处理,后来实在上面的移项过程种想明白的,移项的时候可以把情况<1>和<2>归到一起。我才想明白,其实袋子是否有可能为空并不影响做题,我们可以把空袋子当作一张“隐形卡”,每个状态都默认已经有了这张卡,所以情况<1>可以直接归为情况2,因为不存在空的情况了,隐形卡大家已经收集过了。 




 ===================================================================================================================
 
    方法2:
          其实上述式子可以由条件期望的原理很容易地得出...
          
          首先 E(X|Y=y) =  Σxf(x|y)
               E(E(X|Y)) = EX,  我们叫EX为全体加权平均,E(X|Y)为条件加权平均(局部加权平均),在这道题里X != Y


          这样,我们就可以直接得出上述的公式了:
              E(X|Y)/Σpy = EX  
              Σ(E(Y)*py) / Σpy = EX


          其实条件期望我也是晕晕忽忽的,详细看:http://blog.csdn.net/henhen2002/article/details/5540039
*/
#include <stdio.h>
#define     MAXN    25
double p[MAXN], f[1 << MAXN];
int n;
int main()
{
    while(scanf("%d", &n) != EOF) {
        for(int i = 0; i < n; i++) scanf("%lf", &p[i]);
        f[0] = 0;
        int top = (1 << n);
        for(int u = 1; u < top; u++) {
            double sum = 0, tmp = 0;
            sum += 1;
            for(int i = 0; i < n; i++) if(u & (1 << i)) {
                sum += f[u ^ (1 << i)] * p[i];
                tmp += p[i];
            }
            f[u] = sum/tmp;
        }
        printf("%f\n", f[top-1]);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值