HDU 4336 Card Collector(概率DP+状压)

来源:互联网 发布:淘宝店分类怎么删除 编辑:程序博客网 时间:2024/05/03 17:45
Description
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


题意:N种卡,给出每种卡抽中的概率。每包零食里可能有一种卡,也可能没有。求集齐所有卡片需要买零食数的期望。

思路:

1.dp[i]表示当前拥有的卡的状态为i,要集齐所有卡片的次数的期望。

2.初始状态是,如果我拥有所有的卡,则需要0次购买零食。因此dp[1<<n-1]=0,要求的是dp[0]。

3.先得到零食里没有卡片的概率pp。对于i状态,没有卡片的次数期望为(dp[i]+1)*pp。枚举卡片j,如果已有这张卡,次数的期望是(dp[i]+1)*p[j];没有这张卡,次数的期望为(dp[i|1<<j]+1)*p[j]。三种情况的和等于dp[i]。列方程解出dp[i]。


#include <cstring>#include <vector>#include <map>#include <set>#include <stack>#include <queue>#include <algorithm>#include <iostream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>using namespace std;double p[30];double dp[1<<22];int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        double pp=1.0;        for(int i=0;i<n;i++)        {            scanf("%lf",&p[i]);            pp-=p[i];        }        dp[(1<<n)-1]=0;        for(int i=(1<<n)-2;i>=0;i--)        {            double sum=0;            double x=0;            for(int j=0;j<n;j++)            {                if(i&(1<<j)) x+=p[j];                else sum+=p[j]*(dp[i|(1<<j)]+1);            }            dp[i]=(sum+pp+x)/(1-pp-x);            //dp[i]=(pp+x)*(dp[i]+1)+sum        }        printf("%.5lf\n",dp[0]);    }    return 0;}


0 0