《A First Course in Probability》-chaper3-条件概率和独立性-贝叶斯公式、全概率公式

   设有事件A、B。

    

  下面结合具体的题目进一步理解这种方法:

  Q1:保险公司认为人可以分为两类,一类易出事故,另一类则不易出事故。统计表明,一个易出事故者在一年内发生事故的概率是0.4,而对不易出事故者来说,这个概率可以减小到0.2,若假定第一类人占人口比例的30%,现有一个新人来投保,那么该人在一年内出事故的概率有多大?

  分析:这里我们要求解该人出事故的概率,那么设事件A是该人出事故。而对于事件B,我们当前有三种选择:

(1)    该人是易出事故为事件B1.

(2)    该人不是易出事故为事件B2.

(3)    该人未出事故为事件B3.

  此时我们分别利用上文给出的贝叶斯公式代入计算,此时会发现,(1)(2)的结果是相同的,但是对于(3),我们最终将会推出P(A) = P(A)。而我们很容易看到的一点是,B1、B2和A均是相交集合,而B3则与A是互斥集合。这告诉我们,在应用贝叶斯公式的时候求解事件A的概率时,所选取的第二个事件B应该是与事件A相交的。

 

 

  本质上讲,所谓的全概率公式、贝叶斯公式就是基于独立性的定义和基本的组合原理,将问题进一步程度的抽象。

  全概率公式:

  贝叶斯公式:

   

 

 

  Ex1:

  考虑n张含有一张黑桃“A”的扑克,从第一张扑克开始翻牌,游戏者只有一次猜测机会,可以选择第i次翻牌猜测这张牌是否是黑桃“A”,那么游戏者采取这样的策略能够让获胜几率更大呢?

 

  分析:要解决这个问题,分别讨论第i次猜牌胜利的几率即可

 

    Ex2:

  在回答一道多项选择问题时,学生或者知道正确答案,或者就猜一个。令p表示他知道正确答案的概率,则1-p表示猜的概率。假定学生猜中正确答案的概率为1/m,m就是多项选择题的可选答案数。在已知他回答正确的条件下,该学生知道正确答案的概率是多少?

 

  分析:这是比较典型的贝叶斯公式的应用了,时空上应该知道正确答案然后回答正确,但是现在反过来,正是贝叶斯公式能够处理的。

  

 

 

  Ex3:一项血液化验有95%的把我诊断某种疾病,但是,这项化验用于健康人也会有1%的“伪阳性”结果(即如果一个健康人接受这项化验,则化验结果乌镇此人患有该疾病的概率是0.01)。如果该疾病的患者事实上只占总人口的0.5%,若某人化验结果为阳性,则此人确实患疾病的概率是多少?

  分析:单从问题来看,一般的时空逻辑是像得病,然后化验成阳性,现在的问题变成了已经成阳性,反过来问你真的患病的概率,能够看到是典型的贝叶斯公式的应用。

 

                           

  

  ACM中的概率问题主要涉及到基本的概率公式(全概率、条件概率),然后可能基于递推的思路去解决问题(概率dp),也可能用到数学期望以及一些组合数学中的结论。

 

  Ex4:决斗(uva 1636).

  首先在手枪里随机装一些子弹,然后打了一枪,发现没有子弹。你希望下一枪也没有子弹,是应该直接再开一枪(输出SHOOT),还是转一下再开(输出ROTATE)?如果两种策略下没有子弹的概率相等,输出EQUAL。

  手枪里的子弹看成一个环形序列,开枪一次对准下一个位置。例如,子弹序列为0011,第一次开枪一定在位置1或2,因此开枪之后位置位于2或3.

  分析:很典型的数学问题,解决思维层面在编程计算上几乎没有什么难度。我们分别来看两种策略下没子弹的概率。

  对于直接再打一枪,能够看到它是基于第一枪打孔的条件概率,它的计算方法应该是环形01串中”00”的数量除以”00”、”01”的数量之和,后者其实本质上是整个串中0的数量。

  对于转一下再开枪,这一枪打孔的概率就是0的比率。

  设a是环形01串中“00”个个数,b是“0”的个数,比较a/b和b/n(字符串长)的大小即可。

 

 

  Ex5:麻球。 (uva 11021)

  题目大意:每个麻球的生存周期是一天,一天结束后它可能繁殖出[0,n-1]个麻球,它们的概率分别是P[0]~P[i-1],那么起初k个麻球,在前m天全部死亡的概率是(包括不足m天就死亡的)?

  分析:由各个麻球的独立性,我们其实只需要求解一个麻球进行繁殖,在前m天就全部死亡的概率,假设记为f[m],那么最终结果就是f[m]的k次方.

  那么下面我们面临的问题变成了如何求解f[m]。

  这里就要用到全概率公式,或者理解成动态规划也可以。这里我们通过概率的角度去解释。

 

    因此我们容易得到如下的递推关系式.

 

 

  简单的参考代码如下:

 

 #include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;

const int maxn = 1000 + 10;
const int maxm = 1000 + 10;

int n , k , m;
double P[maxn] , f[maxm];

int main()
{
     int T;
     int tt = 1;
     scanf("%d",&T);
     while(T--)
     {
      memset(f , 0 , sizeof(f));
            scanf("%d%d%d",&n,&k,&m);
               for(int i = 0;i < n;i++)
                   scanf("%lf",&P[i]);

            f[1] = P[0];
            for(int i = 2;i <= m;i++)
            {

                   for(int j = 0;j < n;j++)
                       f[i] += P[j]*pow(f[i-1],j);
            }

            printf("Case #%d: %.7lf\n",tt++ , pow(f[m],k));
     }
     return 0;
}

 

 

  Ex6:蒙提霍尔问题的推广(uva 10491).

  这个问题以蒙提霍尔问题为背景。笔者在《Numberical Methods》的专栏中曾经介绍过,这里将牛、车、主持人打开的门的数量分别记为a、b、c,那么请问在玩家选择了一个门之后,主持人打开c个门后是牛的门,玩家总是采取换门策略的情况下,抽中车的概率。

  利用简单的全概率公式即可。

     

 

 

  Uva11181:

  给出n个人买东西的概率,n个人之见是否买东西是独立的 ,现在问在n个人中k个人买东西的情况下,第i个人买了东西的概率是多少。

  分析:设n个人中k个人买了东西为事件E,第i个人买了东西的事件是Ei,那么根据条件概率的概念,这道问题即是求P(Ei|E)=P(EEi) / P(E)

  现在的问题在于,如何编程计算P(E)和P(EEi),这是一个基于dfs的基本的生成组合的问题。我们即将买的人标记为1,没买的标记为0.

  P(E)需要求出总长为n的01序列中含有k个1的所有序列,然后对应着得到概率,累加之后得到P(E).

  P(EEi)则是求出长度为n的01序列中k个1但是第i个必须是1的所有序列,然后得到对应的概率和,得到P(EEi).

  然后二者相除得到最终的结果。

  参考代码如下:

 

#include<cstdio>
#include<cstring>
using namespace std;

const int maxn = 25;
double pro[maxn];
int visit[maxn];
int n , k;
double pa , pb;
double temp;

void dfs(int num , int now)
{
    if(num == k)
    {
         double p  = 1.0;
         for(int i = 0;i < n;i++)
              {
                  if(visit[i]== 1) p *=  pro[i];
                  //printf("%d",visit[i]);
                  else         p *=  (1 - pro[i]);
              }

              temp += p;
    }



    for(int i = now + 1;i < n;i++)
    {
          if(!visit[i])
          {
               visit[i] = 1;
               dfs(num + 1 , i);
                 visit[i] = 0;

          }

    }


}


int main()
{
  int tt = 1;
     while(scanf("%d %d",&n,&k) &&(n || k))
     {
          printf("Case %d:\n",tt++);
         for(int i = 0;i < n;i++)
               scanf("%lf",&pro[i]);
         temp = 0.0;
         dfs(0 , -1);
         pa = temp;
         //printf("%lf ",pa);



         for(int i = 0;i < n;i++)
         {
              visit[i] = 1;
              temp = 0.0;
              dfs(1 , -1);
              pb = temp;
              //printf("%lf ",pb);

             printf("%.6lf\n",pb/pa);
              visit[i] = 0;

         }

     }
}

 

posted on 2016-07-07 13:51  在苏州的城边  阅读(601)  评论(0编辑  收藏  举报

导航