Alice 與 Bob 的遊戲 (概率DP)

題目描述
Alice 和 Bob 兩個人正在玩一個遊戲,遊戲有很多種任務,難度爲 p 的任務(p是正整數),有 1/(2^p) 的概率完成並得到 2^(p-1) 分,如果完成不了,得 0 分。一開始每人都是 0 分,從 Alice 開始輪流做任務,她可以選擇任意一個任務來做;而 Bob 只會做難度爲 1 的任務。只要其中有一個人達到 n 分,即算作那個人勝利。求 Alice 採取最優策略的情況下獲勝的概率。

輸入格式
一個正整數 n ,含義如題目所述。

輸出格式
一個數,表示 Alice 獲勝的概率,保留 6 位小數。

樣例數據 1
輸入
1
輸出
0.666667

備註
【數據範圍】
對於 30% 的數據,n≤10
對於 100% 的數據,n≤500

由題意可知:
1、只要有一人的分數大於等於n就勝出;
2、對於Alice 每次選分數爲k的任務,成功的概率爲 1/2*k,失敗的概率爲(1-1/2*k);
3、對於Bob 每次只能選分數爲1的任務,成功與失敗的概率均爲 1/2。

首先確定狀態,f[i][j] 爲Alice 爲 i 分,Bob 爲 j 分,Alice要取勝的概率;

然後我們發現可以倒着往前推,先初始化 f[n][] =1,然後由f[n][n] 每次減一個分數;
每次做任務分四種情況:

1、Alice 選擇 得分爲 k 的任務,成功,Bob 選擇得分爲1的任務,也成功了,則:
—-f[ii][j]=f[i+k][j+1]/2*k/2;
2、Alice 選擇 得分爲 k 的任務,成功,Bob 選擇得分爲1的任務,但沒有成功則:
—f[i][j]=f[i+k][j]/2*k/2;
3、Alice 選擇 得分爲 k 的任務,沒有成功,Bob 選擇得分爲1的任務,成功了,則:
—-f[i][j]=f[i][j+1]*(1-1/2*k)/2;
4、Alice 選擇 得分爲 k 的任務,沒有成功,Bob 選擇得分爲1的任務,也沒成功了,則:
—–f[i][j]=f[i][j]*(1-1/2*k)/2;

f[i][j] 的值就等於上面四項之和 ,化簡的方程:
f[i][j]=(f[l][j+1]/k/4+f[l][j]/k/4+f[i][j+1](k*2-1)/k/4)/(1.0-1.0(k*2-1.0)/k/4);

#include<cstdio>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<iomanip>
#include<iostream>
#include<cctype>
#include<algorithm>
#define esp 1e-8
using namespace std;
int n;
double f[505][505],tmp,val;
//---------------------
int main()
{
    scanf("%d",&n);
    for(int i=0;i<=n;i++) f[n][i]=1.0;
    for(int i=n-1;i>=0;i--)
    for(int j=n-1;j>=0;j--){
        val=0;
        for(int k=1;k/2<=n;k<<=1){ // k>=2*n 可能答案更優,比如 n=1,k=2就可以一次勝出
            int l=i+k;  
            if(l>n) l=n;
            double p=1.0/(k*2.0);
            double P=(1.0)/(2.0*k+1.0);
            tmp=f[l][j+1]*P+f[l][j]*P+(1.0-p)*f[i][j+1]/(p+1.0);
            if(tmp>val) val=tmp;
        }f[i][j]=val;
    }
    cout.setf(ios::fixed); 
    cout<<fixed<<setprecision(6)<<f[0][0]<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章