CF98E Help Shrek and Donkey(博弈论)

CF98E Help Shrek and Donkey(博弈论)

题目大意

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

两个人玩游戏轮流操作(其中第一个人为先手)。有如下 (2) 中操作类型:

  1. 猜测:猜桌上的那张牌是什么。如果猜对了则获胜,猜错了则失败。操作完之后游戏结束。

  2. 指定:报一张牌的名字,如果对方手上有这张牌,则将该牌丢弃,游戏继续;如果对方手上没有这张牌,对方则会表示他不用由此牌。

现在假设两个人都知道这 (n+m+1) 张牌分别是什么,但是不知道桌上和对方手里的牌具体是什么。

若双方都采取最优策略进行游戏,问先手和后手获胜概率。

若选手答案与标准答案的误差不超过 (10^{-9}) 则认为正确。

数据范围

数据范围:(0le n,mle 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
", f[n][m], 1 - f[n][m]);
	return 0;
}

原文地址:https://www.cnblogs.com/Hs-black/p/13299508.html