【HDU】4336 Card Collector

http://acm.hdu.edu.cn/showproblem.php?pid=4336

题意:n张卡片,每一次取一个盒子,盒子里装有卡片i的概率是p[i],求得到所有卡片所需要开的盒子的期望数(n<=20)

#include <cstdio>
#include <cstring>
using namespace std;

const int N=22;
int n;
double p[N], f[1<<N];
int main() {
	while(~scanf("%d", &n)) {
		int all=(1<<n)-1;
		for(int i=0; i<n; ++i) scanf("%lf", &p[i]);
		f[all]=0;
		for(int s=all-1; s>=0; --s) {
			double up=1, down=0;
			for(int i=0; i<n; ++i) {
				if(s&(1<<i)) continue;
				up+=f[s|(1<<i)]*p[i];
				down+=p[i];
			}
			f[s]=up/down;
		}
		printf("%f
", f[0]);
	}
	return 0;
}

  

设$f[s]$表示当前得到状态为$s$的卡片还需要开的盒子的期望数:

考虑开一个箱子:

1、没有卡片,概率为:$1-sum_{i} p[i]$;期望和为:$(1-sum_{i} p[i])f[s]$ 

2、卡片$i$已经收集过了,概率为:$p[i]$;期望和为:$sum_{i in s} p[i]f[s]$

3、卡片$i$没有收集过,概率为:$p[i]$;期望和为:$sum_{i otin s} p[i]f[s cup { i }]$

所以

$$
egin{align}
f[s]
& = (1-sum_{i} p[i])f[s] + sum_{i in s} p[i]f[s] + sum_{i otin s} p[i]f[s cup { i }] \
& = frac{1 + sum_{i otin s} p[i]f[s cup { i }]}{sum_{i otin s} p[i]}
end{align}
$$

然后还有注意,spj的话精度一定要注意啊,不要只输出了几位= =,最好多输出几位,你懂的...于是就wa了几发..

原文地址:https://www.cnblogs.com/iwtwiioi/p/4298055.html