题意:
有N(1<=N<=20)张卡片,每包中含有这些卡片的概率为p1,p2,````pN.
每包至多一张卡片,可能没有卡片。
求需要买多少包才能拿到所以的N张卡片,求次数的期望。
可以用状态压缩dp来求概率,做过基本的概率dp后应该没什么问题
这里我主要说说容斥原理的解法。
如果一个事件发生的概率为p, 那么它第一次发生时的次数期望就是1/p
1: 1/p
2: (1-p)*p
3: (1-p)^2*p
......
n: (1-p)^(n-1)*p
以上求和,用错位相消的方法求出 E = 1/p
类似的,我们可以得出 如果两个事件发生的概率分别为p1,p2, 那么
第一次发生其中的某一件的次数期望就是1/(p1+p2)。
根据这个结论我们就可以用容斥原理来做这题了。
容斥:
#include
#include
#include
using namespace std;
int n, two[22];
double p[22], ans;
int main() {
int i, j;
two[0] = 1;
for(i = 1; i <= 20; i++)
two[i] = two[i-1] << 1;
while( ~scanf("%d", &n)) {
for(i = 0; i < n; i++)
scanf("%lf", &p[i]);
ans = 0;
for(i = 1; i < two[n]; i++) {
double sum = 0;
int c = 0;
for(j = 0; j < n; j++)
if(i&two[j]) {
sum += p[j];
c++;
}
if(c&1) ans += 1/sum;
else ans -= 1/sum;
}
printf("%f\n", ans);
}
return 0;
}
状态压缩:
#include
#include
#include
using namespace std;
double p[22], dp[1<<20], p0;
int two[22];
int n;
double tp, ans;
int main() {
int i, j;
two[0] = 1;
for(i = 1; i <= 20; i++)
two[i] = two[i-1] << 1;
while( ~scanf("%d", &n) ) {
p0 = 0;
for(i = 0; i < n; i++) {
scanf("%lf", &p[i]);
p0 += p[i];
}
p0 = 1-p0;
dp[two[n]-1] = 0;
for(i = two[n]-2; i >= 0; i--) {
tp = p0; ans = 1;
for(j = 0; j < n; j++)
if(two[j]&i) tp += p[j];
else ans += p[j]*dp[two[j]|i];
dp[i] = ans/(1-tp);
}
printf("%.5f\n", dp[0]);
}
return 0;
}