HDU-4336 Card Collector(状压概率DP||容斥原理)

Card Collector

http://acm.hdu.edu.cn/showproblem.php?pid=4336

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Special Judge

Problem 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张卡,每次一包方便面,可能有p[i]概率获得第i张卡,也有可能没有卡获得,求拿到全部n张卡需要买的方便面的期望?

解法一:概率DP

感觉做了这么多概率dp,还是离熟悉比较远

合集里看到的,结果一眼就看到是用状态压缩做,然后状态都出来了,转移就没什么难度了...

设dp[i]表示当前取到了i的二进制中位的为1的卡时,离达到目标状态还需要购买方便面的期望,初始状态:dp[(1<<n)-1]=0;

则dp[i]可以转化为:

①:下一袋方便面没有卡,或j卡已有,即:(∑p[j]+pp)*(dp[i]+1);

②:下一袋方面面存在j卡,且当前没有,即:(∑p[j]*(dp[i|(1<<j)]+1);

则状态转移方程为:dp[i]=(∑p[j]+pp)*(dp[i]+1)+∑p[j]*(dp[i|(1<<j)]+1);

化简后得:dp[i]=(∑p[j]*dp[i|(1<<j)]+1)/(1-∑p[j]-pp);

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN=(1<<20)+5;

int n,mx;
double p[25],pp,tmp;//pp表示没有卡的概率
double dp[MAXN];//dp[i]表示当前取到了i的二进制中位的为1的卡时,离达到目标状态还需要购买方便面的期望

int main() {
    while(1==scanf("%d",&n)) {
        mx=1<<n;
        pp=1;
        for(int i=0;i<n;++i) {
            scanf("%lf",p+i);
            pp-=p[i];
        }
        dp[mx-1]=0;
        for(int i=mx-2;i>=0;--i) {
            dp[i]=1;
            tmp=pp;
            for(int j=0;j<n;++j) {
                if((i&(1<<j))==0) {//由仅比i状态多1张卡的状态转移
                    dp[i]+=p[j]*dp[i|(1<<j)];
                }
                else {//tmp表示再买一包时,里面没卡以及卡是已在i状态有时的概率和
                    tmp+=p[j];
                }
            }
            dp[i]/=1-tmp;
        }
        printf("%.4lf\n",dp[0]);
    }
    return 0;
}

解法二:容斥原理

即:含有奇数个事件的概率为加,含有偶数个事件的概率为减

然后统计1~(1<<n)-1的每个状态的期望即可

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN=(1<<20)+5;

int n,mx,cnt;
double p[25],tmp,ans;//tmp表示某一状态下

int main() {
    while(1==scanf("%d",&n)) {
        mx=1<<n;
        ans=0;
        for(int i=0;i<n;++i) {
            scanf("%lf",p+i);
        }
        for(int i=1;i<mx;++i) {
            cnt=0;
            tmp=0;
            for(int j=0;j<n;++j) {
                if((i&(1<<j))!=0) {//统计达到i状态位为1的概率和
                    tmp+=p[j];
                    ++cnt;
                }
            }
            if((cnt&1)==0) {//偶数张卡
                ans-=1.0/tmp;
            }
            else {//奇数张卡
                ans+=1.0/tmp;
            }
        }
        printf("%.4lf\n",ans);
    }
    return 0;
}
时间: 2024-10-11 21:27:57

HDU-4336 Card Collector(状压概率DP||容斥原理)的相关文章

HDU 4336 Card Collector 状压+概率dp

题目链接:点击打开链接 题意: 有n种卡片,每吃一包方便面都有一定概率获得其中一种卡片(也可能不获得卡片) 问集齐n张召唤神龙需要吃的方便面包数的期望. 思路: dp[i] 表示已经拥有卡片的状态为i, 还需要吃多少包才能拥有所有卡片, 显然 dp[(1<<n)-1] = 0; (已经拥有卡片就不用吃了嘛) 而答案就是dp[0]; 用样例二举例,下面dp方程内直接用二进制表示,为了方便观察,我们用最高位表示第一张卡片(P1=0.1),最低位表示第n张卡片(P2=0.4) dp[01]  = (

Hdu 4336 Card Collector (状态概率DP|容斥原理)

详细的题目大意与解析大家参考一下kuangbin的文章. kuangbin链接 这边说一下自己对于kuangbin代码以及容斥原理位元素枚举的理解与解释,希望对大家有所帮助. 状态DP AC代码:状态压缩的思想我就不赘述了,我也只是略懂,这边仅仅分析一下状态方程 由于量比较多,我这边有的便用文字代替,有利于描述. dp[i]表示i状态达到满状态(即收集满n个物品,以下称满状态)所需要的期望. 那么i状态当中收集了x的物品,剩余n-x个物品没有收集 那么dp[i]=p*dp[i]+p2*dp[i2

HDU 4336 Card Collector(动态规划-概率DP)

Card Collector Problem 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

[HDU 4336] Card Collector (状态压缩概率dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4336 题目大意:有n种卡片,需要吃零食收集,打开零食,出现第i种卡片的概率是p[i],也有可能不出现卡片.问你收集齐n种卡片,吃的期望零食数是多少? 状态压缩:f[mask],代表收集齐了mask,还需要吃的期望零食数. 打开包装,有3种情况,第一种:没有卡片,概率(1-sigma(p[i])) 第二种,在已知种类中:概率sigma(p[j]) 第三种,在未知种类中:p[k] 因此 f[mask]

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

Card Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3014    Accepted Submission(s): 1445 Special Judge Problem Description In your childhood, do you crazy for collecting the beautifu

HDU 4336 Card Collector(状压 + 概率DP 期望)题解

题意:每包干脆面可能开出卡或者什么都没有,一共n种卡,每种卡每包爆率pi,问收齐n种卡的期望 思路:期望求解公式为:$E(x) = \sum_{i=1}^{k}pi * xi + (1 - \sum_{i = 1}^{k}pi) * [1 + E(x)]$,即能转换到x情况的期望+x情况原地踏步的期望. 因为n比较小,我们可以直接状压来表示dp[x]为x状态时集齐的期望.那么显然dp[111111111] = 0.然后我们状态反向求解.最终答案为dp[0]. 然后来看期望的求解:$E(x) =

HDU 4336——Card Collector——————【概率dp】

Card Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3407    Accepted Submission(s): 1665Special Judge Problem Description In your childhood, do you crazy for collecting the beautiful

hdu 4336 Card Collector (概率dp+位运算 求期望)

题目链接 Card Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2711    Accepted Submission(s): 1277Special Judge Problem Description In your childhood, do you crazy for collecting the beaut

HDU 4336 Card Collector(概率DP)

 题意:有n种卡片,吃零食的时候会吃到一些卡片,告诉你在一袋零食中吃到每种卡片的概率,求搜集齐每种卡片所需要买零食的袋数的期望. 思路:先状态压缩,然后概率DP 用d[i]表示由状态i到目标需要再买多少包,则状态转移方程为d[i] = p'*(d[i]+1) + sigma(d[ i | (1 << j) * p[i] ),然后相同项移到左边,最后就可以得到答案. #include<cstdio> #include<cstring> #include<cmat