题目链接: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 ",dp[0]); 58 } 59 60 int main() 61 { 62 while(cin>>n) 63 { 64 read(); 65 solve(); 66 print(); 67 } 68 }