1. 程式人生 > >Codeforces 98E Help Shrek and Donkey 納什均衡

Codeforces 98E Help Shrek and Donkey 納什均衡

題意

有n+m+1張牌,牌上的數字互不相同且均在[1,n+m+1]中。A有n張牌,B有m張牌,還有一張牌蓋在桌上。現在A和B輪流操作,當前操作的那一方有兩種操作: 猜蓋在桌上的牌是什麼,若猜對則直接獲勝,猜錯則直接輸。 猜一張對方的手牌,若猜對則對方需要把該牌扔掉,猜錯則沒有影響。 假設雙方都絕頂聰明,問先手獲勝的概率是多少。 n,m1000n,m\le1000

分析

想看比較詳細的題解的話可以參考sam隊長寫的部落格

這題難就難在先手有“欺騙”操作,也就是說,先手可以選擇猜一張我手中的手牌,若後手認為先手在“欺騙”,則先手會丟失一張手牌;反之後手則會認為這張牌就是蓋在桌上的那張,然後直接GG。 首先注意到若無法確定桌上的牌,則先手必然不會去猜桌上的牌。 如果我們把猜對方的手牌稱為“指定”,那麼這時先手就只剩下兩種操作,分別是“欺騙”和“指定”。後手也存在兩種決策,分別是相信和不相信。 若先手選擇“欺騙”,後手選擇“相信”,收益為1

1; 若先手選擇“欺騙”,後手選擇“不相信”,收益為1f(m,n1)1-f(m,n-1); 若先手選擇“指定”,後手選擇“相信”,收益為mm+1(1f(m1,n))\frac{m}{m+1}(1-f(m-1,n)) 若先手選擇“指定”,後手選擇“不相信”,收益為mm+1(1f(m1,n))+1m+1\frac{m}{m+1}(1-f(m-1,n))+\frac{1}{m+1}。 我們設先手選擇“指定”的概率為pp 那麼後手選擇“相信”時先手獲勝概率為(1p)+mm+1(1f(
m1,n))p(1-p)+\frac{m}{m+1}(1-f(m-1,n))p
同理後手選擇“不相信”時先手獲勝的概率為(1f(m,n1))(1p)+(mm+1(1f(m1,n))+1m+1)p(1-f(m,n-1))(1-p)+(\frac{m}{m+1}(1-f(m-1,n))+\frac{1}{m+1})p 由於後手需要讓先手獲勝的概率儘量小,所以先手獲勝的概率就是兩者之中的較小值。而先手又要選擇一個p好讓自己獲勝的概率儘量大。 注意到這是兩條直線,且一條斜率大於0另一條斜率小於0,那麼顯然二者的交點即為答案。 時間複雜度O
(n2)O(n^2)

說實話納什均衡真很有趣,關於納什均衡的一些介紹可以看這篇文章

程式碼

#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;
}