1. 程式人生 > >淺談 概率與期望 DP

淺談 概率與期望 DP

概率與期望DP,一直都不會啊,感覺好難完全沒法思考…

期望題一般是逆推,當然也有一些是順推,然而現在我只做過一些水得很的期望題,好菜啊…

UVa 11021 麻球繁衍 藍書p140

題解:

現在有k只麻球,每隻麻球都只能活一天,但是可能會在死前爆出0到n-1值麻球,機率分別為p0,p1,p2...pn1,求m天后所有麻球都死了的概率,因為每隻麻球是獨立的,這隻麻球並不會導致另一隻麻球死掉,也不會讓另一隻麻球少生幾個麻球,所以我們只需要管最開始有1只麻球,然後最後用乘法原理即可,也就是第一隻麻球死完的概率乘以第二隻麻球死完的概率一直乘到第k只麻球死完的概率,如果有沒有死的那就不行了。
問題轉化為一隻麻球在m天死完的概率,於是我們發現,在第i天死完的機率為生一個蛋的機率乘以(這一個蛋在)第i-1天死完的機率+生兩個蛋的機率乘以(整兩個蛋)在第i-1天死完的機率,也就是一個蛋在i-1天死完的機率乘以一個蛋在i-1天死完的機率。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int T,n,k,m;
const int MAXN=1000+10;
double p[MAXN],dp[MAXN];
double fast_pow(double num,int k){
    double now=num;
    double ans=1.0;
    while(k){
        if(k&1) ans*=now;
        now*=now;k>>=1
; } return ans; } int main(){scanf("%d",&T); for(register int kase=1;kase<=T;kase++){ scanf("%d%d%d",&n,&k,&m); for(register int i=0;i<=n-1;i++) scanf("%lf",&p[i]); dp[0]=0;dp[1]=p[0]; for(register int i=2;i<=m;i++){ dp[i]=0
; for(register int j=0;j<=n-1;j++){ dp[i]+=p[j]*pow(dp[i-1],j); } } double ans=fast_pow(dp[m],k); printf("Case #%d: %0.7lf\n",kase,ans); } return 0; }

這裡寫圖片描述

UVa 11427 玩紙牌

這道題貌似很水,藍書p141,我自己都寫出來了,就是說我們要求的是一天晚上玩兒停了的概率,那麼我們用1除以這個概率就可以了

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int T,n,a,b;
double p,dp[110][110];
int main(){
    scanf("%d",&T);
    for(register int kase=1;kase<=T;kase++){
        scanf("%d/%d %d",&a,&b,&n);
        p=(double)a/b;
        memset(dp,0,sizeof(dp));
        dp[0][0]=1.0;dp[0][1]=0.0;//在地0局,贏0局的概率為1,在第0局,贏1局的概率為0 
        for(register int i=1;i<=n;i++)
        for(register int i=1;i<=n;i++){//一共玩兒的局數應該小於a/b,故j/i<=a/b,即j*b<=i*a 
            for(register int j=0;j*b<=i*a;j++){
                if(j==0){
                    dp[i][j]=dp[i-1][j]*(1.0-p);
                    continue;
                }
                dp[i][j]=dp[i-1][j]*(1.0-p)+dp[i-1][j-1]*p;
            }
        }
        double ans=0.0;
        for(register int j=0;j*b<=a*n;j++) 
            ans+=dp[n][j];
        int final=floor(1/ans);
        printf("Case #%d: %d\n",kase,final);
    }
    return 0;
}

這裡寫圖片描述

POJ 2096

題目大意:

現在有n種bug,有s個子系統,問期望多少次出現bug使得每個系統都有bug並且每個bug至少出現過一次,每次可以出現一種bug,出現概率均等,都為1/n,每次出現的位置(即位於哪個子系統)的概率也均等,都為1/s。

題解:

我們很容易想到用dp[i][j]表示現在的情況,i表示現在收集了n種bug,j表示現在出現在了j個系統中,顯然dp[n][s]時,期望次數為0
顯然dp[i][j]可以從dp[i][j],dp[i+1][j],dp[i][j+1],dp[i+1][j+1]轉移過來,分別表示新出現的bug是舊bug並且出現在舊系統中,新出現的bug是新bug但是出現在舊系統中,新出現的bug之前已經出現過了但是這次出現在了新系統中,和新bug新系統,轉移的概率很顯然,我們把式子列出來之後移項,然後兩邊同時乘以一個n*s,可以化簡運算,顯然答案是dp[0][0]

#include<iostream>
#include<cstdio>
#include<cstring>
double dp[1010][1010];
int n,s;
int main(){
    scanf("%d%d",&n,&s);//n個bug,s個系統
    double ns=n*s;
    dp[n][s]=0.0;
    for(register int i=n;i>=0;i--){
        for(register int j=s;j>=0;j--){
            if(i==n&&j==s) continue;
            dp[i][j]=(ns+((n-i)*j*dp[i+1][j]+(n-i)*(s-j)*dp[i+1][j+1]+i*(s-j)*dp[i][j+1]))/(ns-i*j);
        }
    } 
    printf("%.4lf",dp[0][0]);
    return 0;
}  

這裡寫圖片描述

期望的線性性

首先,什麼是期望?期望就是指一個變數的平均值,當然是加權的,比如這個變數可能是1的概率為百分之五十,可能是2的概率為百分之二十五,可能是5的概率為百分之二十五,那麼期望就是1 *50%+2 *25%+5 *25%
期望具有線性性,期望本來就是描述平均值的,所以一個隨機變數的期望值也就是(x)=Ex
如果現在有個常量,因為他不會變,所有他的期望值為他自己,比如常量c的期望為c,那麼既然如此E(x+c)顯然應該為x的期望值加上c,因為無論如何c都是不變的,所以我們只需要考慮x的期望值就行了,也即可以把x+c當做一個整體,而c這一部分又是不動的,所以我們可以把它提出來,所以E(x+c)=Ex+c,如果是兩個變數的和的期望呢?顯然兩個變數是獨立的,而兩個變數的和是不是應該等於他們兩個變數自己的期望值相加呢?是的,所以E(x+y)=Ex+Ey,如果是乘法呢?顯然如果一個變數乘一個常量的期望值應該可以把常量提出來,因為無論你變數為多少,都要乘這個常量,所以E(x*c)=cEx,當然最後還可以得出E(kx+c)其中k,c為常量,則E(kx+c)=kEx+c

全概率公式:

如果Bn|n=1,2,3...是一個概率空間的有限或者無限可數集,那麼有全概率公式為

P(A)=i=1nP(A|Bi)P(Bi)
貌似很顯然,概率為某B事件發生的概率乘以B事件發生了導致A事件發生的概率的求和

條件期望全期望公式:

pij=P(X=xi,Y=yi)

E(E(Y|X))=niP(X=xi)E(Y|X=xi)

=nipikykpikpi

=nikykpipikpi

=nikykpik

=E(Y)

所以有E(E(Y|X))=E(Y)=niP(X=xi)E(Y|X=xi)