概率dp

概率dp的內容

概率dp 研究有關於概率,步數,期望的等問題。

  • 數學期望 P=Σ每一種狀態*對應的概率。
  • 因爲不可能枚舉完所有的狀態,有時也不可能枚舉完,比如拋硬幣,有可能一直是正面,etc。 但是現在發現大多數題就是手動找公式或者DP推出即可,只要處理好邊界,然後寫好方程,代碼超級簡短。與常規的求解不同,數學期望經常逆向推出。
  • 比如常規的dp[x]可能表示到了x這一狀態有多少,最後答案是dp[n]。而數學期望的dp[x]一般表示到了x這一狀態還差多少,最後答案是dp[0]
  • 什麼時候可以互相計算呢?關鍵在於所求期望的變量值是否會隨着過程變化而變化!!!而不僅僅和所處位置有關!!!這種情況下,我們可以記錄到當前狀態所需的步數,最後就可以算期望。

例題:

 1.甩一個n面的骰子,問每一面都被甩到的次數期望是多少。

SPOJ Favorite Dice(數學期望)

順推:第一次選一張即可達到目的,然後剩下n-1張,從n張中選擇n-1張有用的中的一張,概率是(n-1)/n,故平均每一次期望是n/(n-1),後推求和即可。(平均期望該情況下好算,因此可以順推)。

逆推:已知dp[n]表示所在第n個需要到第n個的期望步數,則dp[n]=0;已知dp[i+1],求dp[i]的解釋:dp[i]=(i/n)*dp[i]+(n-i)/n*dp[i+1]+1,表示:當前第i個到第n個的期望等於,當前期望有i/n的概率在自身,有(n-i)/i的概率到dp[i+1].

 

2.有n個妖怪,每個妖怪有一個固定的戰鬥力c,師傅也有一個初始戰鬥力f0。每天,師傅會隨機選擇一個妖怪決鬥,如果打得贏ft>c,就可以逃出去,逃出去要t[]天,畢竟超人不會飛;
否則,師傅會不甘心,當天他會拿出祕籍練功,將自己變強,f(t+1)=f(t)+c[],第二天尋找下一次機會。
問師傅能夠逃脫可怕的妖怪,繼續追求去印度吃手抓餅的夢想的天數的數學期望day。

ZOJ - 3640 

順推:概率dp,將當前的戰鬥力看成dp[x],每次變成下一個戰鬥力的轉移爲dp[i+c]=dp[i+c]+dp[i]*(i->i+c的概率),則出去的天數的期望爲轉移到狀態*天數,由於有無線個,故無法計算。(概率好求,期望難算)

逆推:用dp[i]表示戰鬥力爲i時出去的期望。最後的結果是成功逃離,因此每種怪都能順利逃離,故當前打這種怪能逃離的期望天數是p*c[j]*c[j],所以如果i>c[j] dp[i]+=(int)(p*c[j]*c[j])/n;,如果i<=c[j] dp[i]+=(dfs(i+c[j])+1)/n;反向打表也即是採用dfs的方式處理,代碼如下:


int n,f;
const double p=(1.0+sqrt(5.0))/2.0;
double dp[maxn];
int c[maxm],t[maxm];

double dfs(int x)
{
    if(dp[x]>0)return dp[x];

    for(int i=0;i<n;i++)
    {
        if(x>c[i])dp[x]=dp[x]+(double)t[i]/n;
        else dp[x]=dp[x]+(dfs(x+c[i])+1.0)/n;
    }
    return dp[x];
}

int main()
{
    while(cin>>n>>f)
    {
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            scanf("%d",&c[i]);
            t[i]=p*c[i]*c[i];
        }
        double ans=dfs(f);
        printf("%.3f\n",ans);
    }
    return 0;
}

 

3.循環型期望dp

 

樣例與代碼:

1.樹形(DAG):

其中p1+p2+p3=1;

struct edge
{
    int to;
    double p;
    double a;//轉移花費,步數等於1
};
vector<edge> vec[maxn];

double e[maxn];
double getE(int rt,int fa)
{
    if(e[rt]>0)return e[rt];
    int s=vec[rt].size();
    for(int i=0;i<s;i++)
    {
        edge v=vec[rt][i];
        if(v.to==fa)continue;
        e[rt]=e[rt]+(getE(v.to,rt)+v.a)*v.p;
    }
    return e[rt];
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章