题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4336
题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率为pi, 每包至多一张卡片,也可能没有卡片, 求需要买多少包才能拿全N张卡片,求次数的期望。
概率DP思路:可以状压枚举每个状态,然后状态间进行转移,注意对于发生状态转移的概率的理解:
如果当前状态能够从n种状态转移得来,则第i种发生的概率为pi/sum(p1....pn)
容斥原理:思路转自:http://m.blog.csdn.net/blog/c3568/9902141
如果一个事件发生的概率为p, 那么它第一次发生时的次数期望就是1/p
如果两个事件发生的概率分别为p1,p2, 那么第一次发生其中的某一件的次数期望就是1/(p1+p2)
以此类推进行容斥
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 21;
double p[maxn];
double dp[1 << maxn];
int main()
{
int n;
while (~scanf("%d", &n))
{
double t = 0;
for (int i = 0; i < n; i++)
{
scanf("%lf", &p[i]);
t += p[i];
}
t = 1 - t;
memset(dp, 0, sizeof(dp));
for (int i = (1 << n) - 2; i >= 0; i--)
{
double a = 0, sum = 1;
for (int j = 0; j < n; j++)
{
if (i & (1 << j))
a += p[j];
else
sum += dp[i | (1 << j)] * p[j];
}
dp[i] = sum / (1 - a - t);
}
printf("%.4f\n", dp[0]);
}
return 0;
}
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 21;
double p[maxn];
int main()
{
int n;
while (~scanf("%d", &n))
{
for (int i = 0; i < n; i++)
scanf("%lf", &p[i]);
double ans = 0;
for (int i = 1; i < (1 << n); i++)
{
double sum = 0;
int cnt = 0;
for (int j = 0; j < n; j++)
{
if (i & (1 << j))
{
sum += p[j];
cnt++;
}
}
if (cnt & 1)
ans += 1.0 / sum;
else
ans -= 1.0 / sum;
}
printf("%.4f\n", ans);
}
return 0;
}