[HDU 4336]Card Collection[状态压缩DP][概率DP][容斥原理]

来源:互联网 发布:期货数据库 编辑:程序博客网 时间:2024/05/29 17:24

题意:

小吃中有N种卡片,每种卡片 i 出现的概率为 pi ,一袋小吃有可能没有卡片,但最多有一张.问集齐所有卡片需要购买小吃的袋数期望.

思路:

1.用状压dp,dp[ s ]表示在s状态时,集齐所需要的袋数期望.

s = 11111表示N = 5时集齐的状态,此时dp[ s ] = 0;

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

因为"期望"是

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

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

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

//281MS8480K#include<cstdio>using namespace std;const int MAXN=22;double p[MAXN];double dp[1<<MAXN];int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        double tt=0;        for(int i=0;i<n;i++)        {            scanf("%lf",&p[i]);            tt+=p[i];        }        tt=1-tt;//tt就表示没有卡片的概率了        dp[(1<<n)-1]=0;//全部收集到了就不需要再买了.求期望一般都是反着推.        for(int i=(1<<n)-2;i>=0;i--)//遍历所有方案        {            double x=0,sum=1;///肯定要拿自己那一张卡片            for(int j=0;j<n;j++)            {                if((i&(1<<j)))x+=p[j];///如果此种卡片在i中已经存在,累加其概率                else sum+=p[j]*dp[i|(1<<j)];///若不存在,说明可以由此种情况转化而来///dp[i|(1<<j)]是"确定事件",p[j]是该确定事件发生的概率,相乘则表示期望.            }            dp[i]=sum/(1-tt-x);        }        printf("%.5lf\n",dp[0]);    }    return 0;}
自己敲一遍:

//250MS  8480K#include<cstdio>using namespace std;const int MAXN = 22;double p[MAXN],dp[1<<MAXN];int main(){    int N,m;    while(scanf("%d",&N)==1)    {        for(int i=0;i<N;i++)            scanf("%lf",p+i);        m = 1 << N ;        dp[m-1] = 0;        for(int i=m-2;i>=0;i--)        {            double sump = 0,sum = 1;            for(int j=0;j<N;j++)            {                if(!(i & (1<<j)))//位运算写成了逻辑与...手残                {                    sump += p[j];//有用的概率                    sum += p[j]*dp[i|(1<<j)];                }            }            dp[i] = sum / sump;        }        printf("%.5lf\n",dp[0]);///虽然样例中输出是保留了3位,但是题中描述是误差1e-4的...所以...    }}
2.容斥原理(先记下,稍后学习...)
//421MS340K#include<iostream>#include<cstdio>using namespace std;double s;  int n,vis[25];double a[25];void dfs(int k,double sum,int cou,int j){    if(cou==k){        s+=1/sum;        return ;    }    for(int i=j;i<=n;i++){            sum+=a[i];            cou++;            dfs(k,sum,cou,i+1);            cou--;            sum-=a[i];    }    return ;}int main(){    while(~scanf("%d",&n)){        for(int i=1;i<=n;i++){            scanf("%lf",&a[i]);        }        double sum=0;        for(int i=1;i<=n;i++)            sum+=(1/a[i]);        for(int i=2;i<=n;i++){            s=0;            dfs(i,0,0,1);            if(i%2==0) sum+=(-1)*s;            else sum+=s;        }        printf("%lf\n",sum);    }}/*HDU 4336容斥原理位元素枚举*/#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>using namespace std;double p[22];int main(){    int n;    while(scanf("%d",&n)==1)    {        for(int i=0;i<n;i++)scanf("%lf",&p[i]);        double ans=0;        for(int i=1;i<(1<<n);i++)        {            int cnt=0;            double sum=0;            for(int j=0;j<n;j++)              if(i&(1<<j))              {                  sum+=p[j];                  cnt++;              }            if(cnt&1)ans+=1.0/sum;            else ans-=1.0/sum;        }        printf("%.5lf\n",ans);    }    return 0;}