题目链接: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