博弈论

最近在刷挑战,做了博弈论专题,然后就成功的入了坑并且爬不上来了......所以今天想总结一下博弈论知识点+习题。

一、巴什博弈

只有一堆n个物品,两个人轮流从这堆物品中取物, 规定每次至少取一个,最多取m个。最后取光者得胜。(百度百科)

我们先考虑m=1的情况,即每人轮流取一个。这种情况下先手的必胜态:很显然就是n%2!=0。由特殊到一般,我们可以将这个公式推广:当m>1时,先手的必胜态:n%(m+1)!=0

附上一道模板题:hdu1846

#include
#include
typedef long long ll;
using namespace std;
int C;
int n, m;
int main()
{
	cin >> C;
	while (C--)
	{
		cin >> n >> m;
		if (n % (m + 1) != 0)
			cout << "first" << endl;
		else
			cout << "second" << endl;
	}
	system("pause");
	return 0;
}

 

二、Nim游戏

有n堆石子,每堆各有ai颗石子。Alice和Bob轮流从非空的石子堆中取走至少1颗石子。Alice先手,取光所有石子的一方获胜。

问谁会获胜?(挑战P311)

对于这种情况应该如何分析呢?分类讨论一下吧。

n=1,显然Alice可以一次取光所有的石子,因此先手必胜。

n=2时,还要分成如下两种情况:

(1)石子数相同:通过作图(虽然很丑),我们会发现此时先手必败。博弈论_第1张图片

(2)石子数不同:虽然初始状态石子数不同,但是由于取石子数没有上限,所以Bob一定可以通过多拿或少拿的操作使石子个数转化成为(1)的状态,所以此时Bob仍然会赢,即先手仍然必败。(如不理解可以在草纸上模拟一下)。

n>=3,有一个结论:a1^a2^...^an=0,先手必败。

证明:

emmm...这个不会证(尴尬...)不过这里下面有一种理解方式,我觉得挺好的。

假设n=3,三堆物品分别有 [x,y,z]

当某人面对 [0,0,0] 这种局面时     这个人一定是输的

当某人面对 [0,n,n] 这种局面时     这个人也是输的

也很好理解   当你面对 [0,n,n] 这种局面时  你从两堆中的某一堆中拿走 k 个      然后你的对手从另一堆中拿走 k 个    一直拿下去  最后面对 [0,0,0] 这种局面的一定是你

当某人面对 [1,2,3] 这种局面时      这个人也是输的

当你面对这种局势时    无论你怎么取     你的对手都能把局势变成 [0,n,n] 这种    例如: 你取走第一堆的 1    然后你的对手就会取走第三堆中的一个    局势变为 [0,2,2]   等等

奇异局势特点     将每堆中物品的个数全部异或之后结果为 0 (尴尬   同样不会证明)

会用到异或的一个小性质      0^x = x        1^x = x'(非x)。

证明内容摘录自https://blog.csdn.net/qq_41021816/article/details/79210074

附上挑战P311代码:

#include
#include
typedef long long ll;
using namespace std;
const int maxn = 1e6+100;
ll a[maxn];
ll n;
int main()
{
	cin >> n;
	int x = 0;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
		x ^= a[i];
	}
	if (x == 0)
		cout << "Alice" << endl;
	else
		cout << "Bob" << endl;
	return 0;
}

 

三、阶梯博弈(Nim升级版)

博弈论_第2张图片

从图中,我们可以看到,当所有石子被移动到0台阶时,游戏结束。也就是说从石子从奇数台阶向偶数台阶变换,不影响游戏胜负状态(因为被移到0位置的石头没用了)。所以我们只要对奇数堆做Nim游戏即可。当对手把偶数堆石子移动到奇数堆时,我们只要将该奇数堆的石子移到下一级偶数阶梯,这样就不会影响奇数堆的Nim博弈了。

附上poj1704结论+代码

结论:当且仅当所有奇数台阶石子数异或和=0,先手必败。

#include 
#include
#include
using namespace std;
typedef long long ll;
int n;
int p[maxn];
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> n;
		for (int i = 1; i <= n; i++)
			cin >> p[i];
		sort(p + 1, p + 1 + n);
		int ans = 0;
		for (int i = n; i >0; i -= 2) {
			ans ^= (p[i] - p[i - 1] - 1);
		}
		if (ans == 0)
			cout << "Bob will win" << endl;
		else
			cout << "Georgia will win" << endl;
	}
	return 0;
}

待补充......

你可能感兴趣的:(博弈)