题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4336
1 0.1 2 0.1 0.4
10.000 10.500
题意:
买东西集齐全套卡片赢大奖。
每个包装袋里面最多一张卡片,最少可以没有。
且给出每种卡片出现的概率 p[i],以及所有的卡片种类的数量 n (1<=n<=20),
求集齐卡片需要买东西的数量的期望值。
注意:包装袋中或许没有卡片;
容斥原理
PS:奇数项和加,偶数项和减!
代码如下:
#include <cstdio> #include <cstring> int main() { int n; double a[47]; while(~scanf("%d",&n)) { for(int i = 0; i < n; i++) { scanf("%lf",&a[i]); } double sum, ans = 0; for(int i = 1; i < (1<<n); i++) { sum = 0; int cnt = 0; for(int j = 0; j < n; j++) { if(i & (1<<j)) { sum+=a[j]; cnt++; } } if(cnt&1) { ans+=1.0/sum; } else { ans-=1.0/sum; } } printf("%lf\n",ans); } return 0; }
dp:
此题中,将n设置为 dp[0];
可以这样想,你要买sum包,才能集齐n种卡片,那么 你最后买的一包一定中奖,即一定是n种中的一种,
用状态压缩表示,dp[1111111]就表示,你现在可以要n包中的一包,也就是可以变成0111111,1011111,1101111.。。。1111110中的一种状态
dp[1111111]=上面列的所有的状态 乘以 中0那包的概率,即dp+=dp[i|(1<<j)]*p[j];
而dp[1111111]表示刚开始,你可以中任一种,它的期望值是0,因为你现在任一种都没有,
dp[0000000]即 dp[0] 则表示现在每一包都有,你已经不用买了,从直观上就可以理解为每位都是0,你没有选择了,
那么,给初值dp[(1<<n)-1]=0,
从这开始,对每一种状态,列举它的每一位,如果是0,则可以变成该位是1的状态,
讲解链接:http://www.bcwhy.com/thread-20576-1-1.html
代码如下:
#include <cstdio> #include <cstring> double p[47], dp[1<<20+1]; int main() { int n; while(~scanf("%d",&n)) { for(int i = 0; i < n; i++) { scanf("%lf",&p[i]); } dp[(1<<n)-1] = 0; for(int i = (1<<n)-2; i >= 0; i--)//枚举所有状态 { dp[i] = 0; double sum = 0; for(int j = 0; j < n; j++)//对每一位枚举 { if(!(i & (1<<j)))//该位是零 { dp[i] += dp[i | (1<<j)]*p[j]; sum+=p[j]; } } dp[i] += 1; dp[i]/=sum;//可以到达i这种状态的状态都找到了 在循环里累加的是期望值 要除概率和 } printf("%lf\n",dp[0]); } return 0; }
HDU 4336 Card Collector(容斥原理 or 状压求期望dp)
原文地址:http://blog.csdn.net/u012860063/article/details/43670387