• hdoj4336(容斥原理or概率DP)


    题目大意:n种卡牌,每种卡牌被抽到的概率依次为P1,P2,,,Pn,抽一次最多抽到一张,最少0张。问抽满n种卡的次数的期望。

     

    用容斥原理来做,先单独考虑,再减去重复的。比如有两种卡牌A,B,分别为p1,p2,抽到A牌的期望为1/p1,抽到B牌的期望为1/p2,然而抽A牌时会有对B牌的重复,抽B牌亦然。根据容斥原理,减去两者的并部分(这个并部分似乎在这里有些难以理解,对于概率论没学好的我。。。),这个并部分即抽到A或B的期望。即E=E1+E2-E(12)=1/p1 + 1/p2 - 1/(p1+p2)。

    卡牌多了,奇加偶减。

    AC代码:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<iostream>
     4 
     5 using namespace std; 
     6 
     7 double a[30];
     8 
     9 double solve(int x)
    10 {    int n=(1<<x)-1;  //二进制枚举
    11     double sum=0;
    12     for(int j=1;j<=n;j++)
    13     {
    14         int flag=0;
    15         double sum2=0;
    16     for(int i=0;i<x;i++)
    17         {
    18             if(j&(1<<i))
    19             {
    20                 flag++;
    21                 sum2+=a[i+1];
    22             }
    23         }
    24         if(flag&1) sum+=1/sum2;
    25         else sum-=1/sum2;
    26     }
    27     return sum;
    28 }
    29 int main()
    30 {    int n;
    31     while(~scanf("%d",&n))
    32     {    for(int i=1;i<=n;i++)
    33             scanf("%lf",&a[i]);
    34         double sum=solve(n);    
    35         printf("%.5f
    ",sum);
    36     }
    37     
    38     
    39     
    40     return 0;
    41 }

    另一种做法:概率dp

    像状压DP一样,1表示已经取到了这种卡,0表示还没。

    先看个例子,假设有10种卡,每种卡片被抽到的概率均为0.1,dp分析,假如我们已经抽到了k种卡片,那么再抽到一种新的卡片(第k+1种)的概率即为(10-k)/10,再抽到这种卡片的期望次数即为10/(10-k)。

    所以,dp[k+1] = dp[k] +  10/(10-k);

    当然,本题概率并不均等,还可能抽一次,毛都没有。

    上面的式子也是化简后的式子,因为还需考虑是哪k种卡片,第k+1种又是哪一种。

    期望一般逆推:

    dp[k]=sum{dp[k+1]*P(k->k+1)}+P(n-k)

    设dp[(1<<n)-1]为0,这样得出的答案与原来的状态呈反序,好强啊。

    代码:

     1 #include <iostream>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <cstdio>
     5 using namespace std;
     6 const int maxn = 20;
     7 double dp[1<<maxn], p[maxn];
     8 int main()
     9 {
    10     int n;
    11     while(~scanf("%d", &n))
    12     {
    13         double cur = 0;
    14         for(int i = 0; i < n; i++)
    15         {
    16             scanf("%lf", &p[i]);
    17             cur += p[i];
    18         }
    19         
    20         int last = (1 << n)-1;
    21         dp[last]=0; 
    22         for(int i = last-1; i >= 0; i--) 
    23         {
    24             double temp = 1-cur; //抽到空的概率 
    25             double k=0;
    26             for(int j = 0; j < n; j++)
    27             {
    28                 if((1<<j)&i) temp += p[j];
    29                 else k += dp[i|(1 << j)]*p[j]; //
    30             }
    31             dp[i] = k/(1-temp)+1.0/(1-temp);
    32 
    33         }
    34         printf("%.5f
    ", dp[0]);
    35     }
    36     return 0;
    37 }
    View Code2
  • 相关阅读:
    解释器模式
    java-->Hashtable简单使用
    HashTable和HashMap区别
    享元模式
    Beanutils.copyProperties( )用法
    删除List集合中的元素方法
    Date中before和after方法的使用
    Spring定时任务@Scheduled注解使用方式
    Oracle中INSTR、SUBSTR和NVL的用法
    StringBuffer的delete方法与deleteCharAt方法的区别。
  • 原文地址:https://www.cnblogs.com/lnu161403214/p/8309545.html
Copyright © 2020-2023  润新知