1. 程式人生 > 實用技巧 >CF98E Help Shrek and Donkey(博弈論)

CF98E Help Shrek and Donkey(博弈論)

CF98E Help Shrek and Donkey(博弈論)

題目大意

有一副互不相同的牌共 \(n+m+1\) 張。有兩個人,第一個人 \(n\) 張,第二個人 \(m\) 張。另外有一張牌放在桌子上。

兩個人玩遊戲輪流操作(其中第一個人為先手)。有如下 \(2\) 中操作型別:

  1. 猜測:猜桌上的那張牌是什麼。如果猜對了則獲勝,猜錯了則失敗。操作完之後遊戲結束。

  2. 指定:報一張牌的名字,如果對方手上有這張牌,則將該牌丟棄,遊戲繼續;如果對方手上沒有這張牌,對方則會表示他不用由此牌。

現在假設兩個人都知道這 \(n+m+1\) 張牌分別是什麼,但是不知道桌上和對方手裡的牌具體是什麼。

若雙方都採取最優策略進行遊戲,問先手和後手獲勝概率。

若選手答案與標準答案的誤差不超過 \(10^{-9}\) 則認為正確。

資料範圍

資料範圍:\(0\le n,m\le 1000\)

解題思路

博弈論神題

如果你認為這只是一道簡單的概率 dp,那麼 E 題的稱號將臭名昭著

這題難在你猜對方,對方發現你沒猜中,那麼那張牌一定是桌子上的嗎?顯然不是,你可以故意猜自己手中的牌,誘使對方猜錯

啊這,博弈論還可以欺騙的話還怎麼玩啊(主要是不好做題)

\(f[n][m]\) 表示先手贏的概率,\(p\) 表示先手猜測的概率,列出一個表格

相信 不信
欺騙 \(a = 1\) \(b = (1-f[m][n-1])\)
猜測 \(c = \frac m{m+1}(1-f[m-1][n])\) \(d = \frac m{m+1}(1-f[m-1][n])+\frac 1{m+1}\)

那麼使 \(p*c+(1-p)*a=p*d+(1-p)*b\) 即可

為什麼是這樣,難道後手可以猜到先手的欺騙的概率,或先手猜到後手的相信的概率嗎

考慮如果後手一直選擇相信或不信,那麼可以看到先手的收益是兩條斜率正負不同的直線,但後手總可以根據先手兩條直線的斜率大小確定自己最適合的“相信概率”,而這個概率能讓先手在交點處以外的點都沒有在交點處更優,所以先手選交點即可

程式碼

const int N = 2005;
int m, n;
double f[N][N];
int main() {
	read(n), read(m); int mx = max(n, m);
	for (int i = 0;i <= mx; i++) f[i][0] = 1;
	for (int i = 1;i <= mx; i++) f[0][i] = 1.0 / (i + 1);
	for (int i = 2;i <= n + m; i++) {
		for (int j = 1;j < i; j++) {
			if (i - j < 1) continue;
			int x = j, y = i - j;
			double inv = 1.0 / (y + 1);
			double c = inv * y * (1 - f[y-1][x]), b = (1 - f[y][x-1]);
			double d = c + inv;
			double p = (1.0 - b) / (1 - c + d - b);
			f[x][y] = p * c + (1 - p);
		}
	}
	printf ("%.9lf %.9lf\n", f[n][m], 1 - f[n][m]);
	return 0;
}