当前位置: 代码迷 >> 综合 >> HDU 4336 Card Collector (概率-期望DP)【模板】
  详细解决方案

HDU 4336 Card Collector (概率-期望DP)【模板】

热度:56   发布时间:2023-12-23 00:18:19.0

先解释一下期望值得定义,个人觉得比较难理解,跟以前书上了解的不太一样。

求期望的题,对于dp的定义一般都是从终态转移到初态,也就是反着求.

因为"期望"是

确定事件的结果 * 该事件发生的概率 = 平均来看尝试一次可以得到的结果,即期望

若是在s1状态得到一张卡片转移到了s2,那么s2是一个确定的状态,而在s1时则有多种可能性.由此可以理解反着求的合理性.

终态是初态的"去向",确是期望的"来源".


 下面来看题:

In your childhood, do you crazy for collecting the beautiful cards in the snacks? They said that, for example, if you collect all the 108 people in the famous novel Water Margin, you will win an amazing award. 

As a smart boy, you notice that to win the award, you must buy much more snacks than it seems to be. To convince your friends not to waste money any more, you should find the expected number of snacks one should buy to collect a full suit of cards.
Input
The first line of each test case contains one integer N (1 <= N <= 20), indicating the number of different cards you need the collect. The second line contains N numbers p1, p2, ..., pN, (p1 + p2 + ... + pN <= 1), indicating the possibility of each card to appear in a bag of snacks. 

Note there is at most one card in a bag of snacks. And it is possible that there is nothing in the bag.
Output
Output one number for each test case, indicating the expected number of bags to buy to collect all the N different cards. 

You will get accepted if the difference between your answer and the standard answer is no more that 10^-4.
Sample Input
1
0.1
2
0.1 0.4
Sample Output
10.000
10.500

 【题解】

 好好来说一下这个题,网上给的解释看的我好费神,理解了好久。

 这题和以前的题不一样的地方是抽出每张卡片的概率都不一样,这样就不能用dp[i]来表示i的期望值,因为有n张卡片,所以要用二进制表示的1<<n种状态来表示每种状态到抽齐所有卡片需要的期望数,0表示还没抽出来,1表示已经抽到了。

 那么从后往前推,已知最后一种状态dp[(1<<n)-1]=0,因为这时候已经集齐了,往前遍历,前一种状态dp[(1<<n)-2]转移到最后一种状态需要的袋数期望值就是当前状态为0是位置的概率乘抽到该卡片后的袋数期望值。

这就是状态转移了,具体看代码:

【AC代码】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=20;
int n;
double dp[1<<N];
double p[N];int main()
{while(~scanf("%d",&n)){double pp=0;for(int i=0;i<n;++i){scanf("%lf",&p[i]);pp+=p[i];}pp=1-pp;//抽不到卡片的概率dp[(1<<n)-1]=0;//最终状态为1111...1时需要买的期望数是0for(int i=(1<<n)-2;i>=0;--i)//遍历所有状态{double x=0;double s=1;//先买一包  至于里面有什么卡片或者没有卡片就要分情况了for(int j=0;j<n;++j)//遍历所有卡片类型{if(i&(1<<j))/*如果该卡片已经开出来了*/  x+=p[j]; //则把这部分的概率累加一下else s+=p[j]*dp[i|(1<<j)];//如果该卡片第一次开出来,那么就准备状态转移,凡是没开出来的(0)状态位置都可以转移,把转移到每个位置的期望都加起来} //简单点讲,就是比如现在二进制状态是101101,那么把当前的1放到第一个0位置处的期望就是0处的概率p[i]*把0换成1后的期望dp[i]=s/(1-pp-x);//总的期望值除以抽到未开出卡片的概率就是期望值}printf("%.4f\n",dp[0]);//推到初始状态;}return 0;
}