最近在刷挑战,做了博弈论专题,然后就成功的入了坑并且爬不上来了......所以今天想总结一下博弈论知识点+习题。
只有一堆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;
}
有n堆石子,每堆各有ai颗石子。Alice和Bob轮流从非空的石子堆中取走至少1颗石子。Alice先手,取光所有石子的一方获胜。
问谁会获胜?(挑战P311)
对于这种情况应该如何分析呢?分类讨论一下吧。
n=1,显然Alice可以一次取光所有的石子,因此先手必胜。
n=2时,还要分成如下两种情况:
(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;
}
从图中,我们可以看到,当所有石子被移动到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;
}
待补充......