某不知名的題 - 概率DP

兩名玩家進行對戰,P1擁有N點血量,P2用有M點血量。

兩人均有一定概率可以打出1-6點上海,每次兩名玩家進行對戰的時候,傷害高的一方可以打掉傷害低的一方一點血量。

已知N,M以及兩名玩家的攻擊力概率。求P1是勝利的概率。

輸入

多組輸入,魅族輸入兩個整數N,M表示玩家的血量(1<=N,M<=2000)

隨後輸入兩組浮點數每組6個浮點數,分別表示P1,P2打出1-6傷害的概率。

輸出

對於每組輸入輸出P1的勝率(輸入保留兩位小數)


示例輸入

5 5

1.00 0.00 0.00 0.00 0.00 0.00

0.00 0.00 0.00 0.00 0.00 1.00

示例輸出

0.00

思路:我們用二維dp數組表示出p1的血量和p2的血量分別到達a和b的概率即dp[a][b],這是我們假設p1和p2贏的概率爲wp1和wp2,現在有狀態轉移方程

dp[a][b]=dp[a-1][b]*wp2+dp[a][b-1]*wp1

但是我們沒有考慮到平局的情況,假設平局概率爲f對於dp[a-1][b]到達dp[a][b]可能直接p2贏也可能平一局,也或許平3局所以

dp[a][b]=dp[a-1][b]*(wp2+f*wp2+f^2*wp2+...+f^n*wp2)+dp[a][b-1]*(wp1+f*wp1+f^2*wp1+...+f^n*wp1)

提出wp2剩餘一個等比數列,由前n項和且f^n趨近於0可得前n項和爲1/(1-f)

dp[a][b]=dp[a-1][b]*wp2/(1-f)+dp[a][b-1]*wp1/(1-f)

以上就是狀態轉移方程

我們最後只需要將dp[i][m](0<=i<=n-1)相加得到最終答案

注意:dp不能直接遞推到dp[i][m]當p2到達m狀態時p1已經獲勝,不能繼續遞推到下個狀態。


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;

double dp[2010][2010];
int main()
{
    double p1[7],p2[7];
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        double wp1=0,wp2=0,f12=0;
        for(int i=0;i<6;i++)
        {
            scanf("%lf",&p1[i]);
        }
        for(int i=0;i<6;i++)
        {
            scanf("%lf",&p2[i]);
        }
        for(int i=1;i<6;i++)
        {
            for(int j=0;j<i;j++)
            {
                wp1 += p1[i]*p2[j];
            }
        }
        for(int i=1;i<6;i++)
        {
            for(int j=0;j<i;j++)
            {
                wp2 += p2[i]*p1[j];
            }
        }
        for(int i=0;i<6;i++)
        {
            f12 += p1[i]*p2[i];
        }
        wp1/=(1-f12);
        wp2/=(1-f12);
        dp[0][0]=1;
        for(int i=1;i<=n;i++)
        {
            dp[i][0]=(dp[i-1][0]*wp2);
        }
        for(int i=1;i<=m;i++)
        {
            dp[0][i]=(dp[0][i-1]*wp1);
        }
        for(int i=1;i<n;i++)
        {
            for(int j=1;j<m;j++)
            {
                dp[i][j]=(dp[i-1][j]*wp2+dp[i][j-1]*wp1);
            }
        }
        double ans=0;
        for(int i=0;i<n;i++)
        {
            ans += dp[i][m-1]*(wp1);
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}


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