概率DP 狀壓DP 條件期望DP 好題
題意:有n種卡片,一袋面裏有一張卡片或者沒有。給出每種卡片出現在一袋面裏的概率,問要收集完n種卡片所需要買的袋面數目的期望(n <= 20).
思路:狀壓表當前已收集到的卡片的狀態,位爲1表收集到了,0表沒有收集到。
對於狀態T,考慮最近買的那袋面之前的狀態S(也就是狀態X在買了這袋面之後變成了狀態T),
<1>這袋面沒有卡片
<2>這袋面的卡片X已經收集過了
<3>這袋面的卡片X還沒有收集過
方法1:
前兩種情況新舊狀態不變,即T = S;後面一種情況S = T ^ (1<<k)
則T數學期望E(T) = 1 + (1 - Σp[i])*E(T) + Σ(p[j]*E(T)) + Σ(p[k]*E(S))
其中:i = 0, 1, 2,...n-1
j = 第j種卡片已經收集過了,S & (1<<j) == 1
k = 第k種卡片還沒有收集過,S & (1<<j) == 0
移項可得:E(T) * Σp[k] = 1 + Σ(p[k] * E(S) ,這裏的k=第k種卡片沒收集到,S = T ^ (1<<k)
ps:我之前一直很奇怪爲什麼大家的代碼沒有對“袋面裏可能沒有卡片”這一點做處理,後來實在上面的移項過程種想明白的,移項的時候可以把情況<1>和<2>歸到一起。我纔想明白,其實袋子是否有可能爲空並不影響做題,我們可以把空袋子當作一張“隱形卡”,每個狀態都默認已經有了這張卡,所以情況<1>可以直接歸爲情況2,因爲不存在空的情況了,隱形卡大家已經收集過了。
===================================================================================================================
方法2:
其實上述式子可以由條件期望的原理很容易地得出...
首先 E(X|Y=y) = Σxf(x|y)
E(E(X|Y)) = EX, 我們叫EX爲全體加權平均,E(X|Y)爲條件加權平均(局部加權平均),在這道題裏X != Y
這樣,我們就可以直接得出上述的公式了:
E(X|Y)/Σpy = EX
Σ(E(Y)*py) / Σpy = EX
其實條件期望我也是暈暈忽忽的,詳細看:http://blog.csdn.net/henhen2002/article/details/5540039
*/
#include <stdio.h>
#define MAXN 25
double p[MAXN], f[1 << MAXN];
int n;
int main()
{
while(scanf("%d", &n) != EOF) {
for(int i = 0; i < n; i++) scanf("%lf", &p[i]);
f[0] = 0;
int top = (1 << n);
for(int u = 1; u < top; u++) {
double sum = 0, tmp = 0;
sum += 1;
for(int i = 0; i < n; i++) if(u & (1 << i)) {
sum += f[u ^ (1 << i)] * p[i];
tmp += p[i];
}
f[u] = sum/tmp;
}
printf("%f\n", f[top-1]);
}
return 0;
}