Codeforces 98E Help Shrek and Donkey 納什均衡
阿新 • • 發佈:2018-12-13
題意
有n+m+1張牌,牌上的數字互不相同且均在[1,n+m+1]中。A有n張牌,B有m張牌,還有一張牌蓋在桌上。現在A和B輪流操作,當前操作的那一方有兩種操作: 猜蓋在桌上的牌是什麼,若猜對則直接獲勝,猜錯則直接輸。 猜一張對方的手牌,若猜對則對方需要把該牌扔掉,猜錯則沒有影響。 假設雙方都絕頂聰明,問先手獲勝的概率是多少。
分析
想看比較詳細的題解的話可以參考sam隊長寫的部落格。
這題難就難在先手有“欺騙”操作,也就是說,先手可以選擇猜一張我手中的手牌,若後手認為先手在“欺騙”,則先手會丟失一張手牌;反之後手則會認為這張牌就是蓋在桌上的那張,然後直接GG。 首先注意到若無法確定桌上的牌,則先手必然不會去猜桌上的牌。 如果我們把猜對方的手牌稱為“指定”,那麼這時先手就只剩下兩種操作,分別是“欺騙”和“指定”。後手也存在兩種決策,分別是相信和不相信。 若先手選擇“欺騙”,後手選擇“相信”,收益為; 若先手選擇“欺騙”,後手選擇“不相信”,收益為; 若先手選擇“指定”,後手選擇“相信”,收益為 若先手選擇“指定”,後手選擇“不相信”,收益為。 我們設先手選擇“指定”的概率為 那麼後手選擇“相信”時先手獲勝概率為 同理後手選擇“不相信”時先手獲勝的概率為 由於後手需要讓先手獲勝的概率儘量小,所以先手獲勝的概率就是兩者之中的較小值。而先手又要選擇一個p好讓自己獲勝的概率儘量大。 注意到這是兩條直線,且一條斜率大於0另一條斜率小於0,那麼顯然二者的交點即為答案。 時間複雜度。
說實話納什均衡真很有趣,關於納什均衡的一些介紹可以看這篇文章。
程式碼
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
const int N=1005;
int n,m;
double f[N][N];
double dp(int n,int m)
{
if (f[n][m]>0) return f[n][m];
if (!m) return 1;
if (!n) return 1.0/(m+1);
double k1=(1.0-dp(m-1,n))*m/(m+1)-1.0,k2=dp(m,n-1)-dp(m-1,n)*m/(m+1);
double b1=1,b2=1.0-dp(m,n-1);
double p=(b2-b1)/(k1-k2);
return f[n][m]=1.0-p+p*(1.0-dp(m-1,n))*m/(m+1);
}
int main()
{
scanf("%d%d",&n,&m);
double ans=dp(n,m);
printf("%.10lf %.10lf\n",ans,1.0-ans);
return 0;
}