NKOJ 2127 搜集卡片
问题描述
童年时代,你是否热衷于搜集零食里的卡片呢?比如你集齐了108张水浒英雄的卡片,你会感到非常有成就感,而且还可以去兑换奖品。
作为一个聪明的小孩,你注意到如果你要赢得奖品,你必须买很多很多的零食才能搜集齐卡片。要赢得奖品,你估计要买多少袋零食才能成功?
输入格式
第一行,一个整数N(1 <= N <= 20), 表示总共有N种不同的卡片。
第二行,N个空格间隔的实数p1, p2, …, pN, (p1 + p2 + … + pN <= 1), 表示零食袋中每种卡片出现的概率。
注意:一包零食中最多有一张卡片,也可能一张都没有。
输出格式
一个实数,表示你计算的结果,保留6位小数
样例输入
2
0.1 0.4
样例输出
10.500000
数学期望水题,权当是复习。
显然应该用递推的方式解决此问题,为了递推我们需要记录状态,这道题记录状态显然用状态压缩。
设
f[x]
表示在
x
的二进制表示的状态下,要全部搜集完需要买零食的期望值。那么有初值
接下来考虑递推式:
f[x]=p没有卡片f[x]+p得到已有的卡片f[x]+∑当前状态没有i号卡片pif[x|(1<<i−1)]+1
由于有
1−p没有卡片−p得到已有的卡片=p得到没有的卡片
,移项后整理得:
f[x]=(∑当前状态没有i号卡片pif[x|(1<<i−1)]+1)÷p得到没有的卡片
代码:
#include<stdio.h>
int N,En;
double f[1048576+233],p[25];
int main()
{
int i,j;
double P,sum;
scanf("%d",&N);
for(i=1;i<=N;i++)scanf("%lf",&p[i]);
En=(1<<N)-1;
for(i=En-1;i>=0;i--)
{
sum=P=0;
for(j=1;j<=N;j++)if(!(i&(1<<j-1)))sum+=p[j]*f[i|(1<<j-1)],P+=p[j];
f[i]=(sum+1)/P;
}
printf("%.6lf",f[0]);
}