題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4336
題意:
有n種卡片(n <= 20)。
對于每一包方便面,里面有卡片i的概率為p[i],可以沒有卡片。
問你集齊n種卡片所買方便面數量的期望。
?
題解:
狀態壓縮。
第i位表示手上有沒有卡片i。
?
表示狀態:
dp[state] = expectation
(卡片狀態為state時,要集齊卡片還要買的方便面數的期望)
?
找出答案:
ans = dp[0]
剛開始一張卡片都沒有。
?
如何轉移:
now: dp[state]
對于卡片i,如果手上已經有了i,則方便面里有i等價于面里什么都沒有。
所以子期望共兩種:
(1)拿到一張還沒有的卡片i。
(2)拿到垃圾2333。
dp[state] = sigma( dp[state|(1<<i)] * p[i] ) + dp[state] * P(useless) + 1
P(useless)為拿到垃圾的概率。
設tot = sigma(p[i])
P(useless) = 1 - tot
原式移項后:
dp[state] = ( sigma( dp[state|(1<<i)] * p[i] ) + 1 ) / tot
?
邊界條件:
dp[(1<<n)-1] = 0
已經集齊,不用再買。
?
AC Code:
1 // state expression: 2 // dp[state] = expectation 3 // state: state of present cards 4 // 5 // find the answer: 6 // ans = dp[0] 7 // 8 // transferring: 9 // now: dp[state] 10 // dp[state] = sigma( dp[state|(1<<i)] * p[i] ) + dp[state] * P(useless) + 1 11 // i: not been collected 12 // dp[state] = ( sigma( dp[state|(1<<i)] * p[i] ) + 1 ) / (1 - P(useless)) 13 // dp[state] = ( sigma( dp[state|(1<<i)] * p[i] ) + 1 ) / tot 14 // 15 // boundary: 16 // dp[(1<<n)-1] = 0 17 #include <iostream> 18 #include <stdio.h> 19 #include <string.h> 20 #define MAX_N 25 21 #define MAX_S ((1<<20)+5) 22 23 using namespace std; 24 25 int n; 26 double p[MAX_N]; 27 double dp[MAX_S]; 28 29 void read() 30 { 31 for(int i=0;i<n;i++) 32 { 33 cin>>p[i]; 34 } 35 } 36 37 void solve() 38 { 39 memset(dp,0,sizeof(dp)); 40 for(int state=(1<<n)-2;state>=0;state--) 41 { 42 double tot=0; 43 for(int i=0;i<n;i++) 44 { 45 if(!((state>>i)&1)) 46 { 47 dp[state]+=dp[state|(1<<i)]*p[i]; 48 tot+=p[i]; 49 } 50 } 51 dp[state]=(dp[state]+1.0)/tot; 52 } 53 } 54 55 void print() 56 { 57 printf("%.9f\n",dp[0]); 58 } 59 60 int main() 61 { 62 while(cin>>n) 63 { 64 read(); 65 solve(); 66 print(); 67 } 68 }
?