1. 程式人生 > 其它 >CF98E Help Shrek and Donkey

CF98E Help Shrek and Donkey

一、題目

點此看題

二、解法

首先我們要弄清楚先後手玩遊戲大致用什麼策略,由於每張牌都是等價的,所以亂猜還不如去調戲一下對手,那麼感性理解在不確定桌上卡牌的情況下,先後手是不會使用猜測操作的,證明

因為如果詢問操作後對方沒有棄牌,那麼後手可以認為牌是在牌堆,從而做出猜測操作。這題有趣的地方是可以詢問自己的手牌,可以誘導後手輸掉,但是後手也可以選擇相信或者不相信。

\(f(n,m)\) 為先手選 \(n\) 張牌,後手選 \(m\) 張牌的概率,我們可以列一個策略的表格:

先後手 ............................詢問............................ ............................欺騙............................
詢問 \(\frac{m}{m+1}(1-f(m-1,n))\) \(\frac{1}{m+1}+\frac{m}{m+1}(1-f(m-1,n))\)
欺騙 \(1\) \(1-f(m,n-1)\)

就拿先手詢問,後手認為先手是欺騙的情況來說吧,其他情況可以類似推導。此時有 \(\frac{1}{m+1}\) 的概率抽中桌上的卡牌,但是後手以為先手在欺騙無動於衷,所以先手可以在以後的操作中直接猜測,必勝。有 \(\frac{m}{m+1}\) 的概率抽中對方的手牌,那麼此時先後手交換,原來的後手可以看成失去了一張牌,所以原來後手的勝率是 \(f(m-1,n)\)

,原來先手的勝率是 \(1-f(m-1,n)\)

設先手有 \(p\) 的概率詢問,\(1-p\) 的概率欺騙,設表格中的概率按從左到右的順序分別是 \(a,b,c,d\),那麼:

\[pa+(1-p)c=pb+(1-p)d \]\[p=\frac{d-c}{a-b-c+d} \]

那麼可以根據 \(p\) 來轉移了,但是為什麼要這樣做呢?下面給出解釋(感謝 \(\tt Charlotte\) 大佬的講解):

“主要是兩人其實除了自己和對方有幾張牌以外就沒有其他資訊了”

“所以操作基本只能基於當前局面”

“而基於當前局面,可以選擇欺騙或猜測兩種方案”

“那這兩種方案並沒有哪一個是必定佔優勢的”

“就只能平衡兩者的收益,按某種概率選擇其中一種策略,來達到期望最優”

上面這段話解釋了為什麼先手要按照概率 \(p\) 來決策,那麼解出 \(p\) 的等式是怎麼來的呢?後手選擇 認為先手詢問 和 認為先手欺騙 的收益應該是相同的,否則後手會傾向收益高的那邊,那麼先手就會調整 \(p\) 使得兩者相同。

三、總結

資訊不對等博弈可以考慮按概率決策,並且尋找收益平衡點。

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 1005;
#define db double
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m;db g[M][M];
db f(int n,int m)
{
	if(g[n][m]) return g[n][m];
	db a=m*(1-f(m-1,n))/(m+1.0),b=1/(m+1.0)+a;
	db c=1,d=1-f(m,n-1),p=(d-c)/(a-c-b+d);
	return g[n][m]=p*a+(1-p)*c;
}
signed main()
{
	n=read();m=read();
	for(int i=0;i<=max(n,m);i++)
		g[i][0]=1,g[0][i]=1.0/(i+1);
	printf("%.10f %.10f\n",f(n,m),1-f(n,m));
}