巴氏博弈
eg:hdu2149,2156
描述:只有一堆n個石子,每次能取1到m個物品,A先手,問誰能先取完石子
思路:這種問題的關鍵就在於能否取到關鍵點,比如,這裏只能能取到倒數m+2個石子,留下m+1個石子,則後者就必敗。
結論:如果初始石子是(m+1)的倍數,則先手必敗,否則先手必勝。
威佐夫博弈
eg:hdu2177,hdu5754
描述:有兩堆物品,每堆都有若干物品。每次可以從一堆中取任意物品,也可以從兩堆中取一樣多的任意個物品。先取光者獲勝。
思路:就是枚舉必敗態發現規律(最終思想sg函數差不多之後會介紹一下sg函數),可以枚舉前幾個必敗態,(0, 0), (1, 2), (3, 5), (4, 7), (6, 10), (8, 10)…..
最後得到結論:
ak=[k1+5√2],bk=ak+k
代碼判斷:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int x1, x2, temp;
while(scanf("%d%d", &x1, &x2) != EOF) {
if(x1 > x2) swap(x1, x2);
temp = floor((x2 - x1) * (1 + sqrt(5.0)) / 2.0);
if(temp == x1) cout << "後手贏" << endl;
else cout << "先手贏" << endl;
}
return 0;
}
尼姆博弈
描述:有n堆石子,每堆有ai 個,兩人輪流從一堆中取任意個物品,誰把最後一個石子取光誰贏
結論:把所有石子個數異或起來,值爲0則先手敗,值爲1則先手勝。
代碼判斷:
#include<bits/stdc++.h>
using namespace std;
int a[11111];
int main()
{
int n;
while(scanf("%d", &n) != EOF) {
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
int ans = 0;
for(int i = 1; i <= n; i++) {
ans ^= a[i];
}
if(ans == 0) cout << "後手勝" << endl;
else cout << "先手勝" << endl;
}
return 0;
}
eg:hdu1907這題需求和尼姆相反,取完最後一個的失敗,所以綜上所述,結論是,如果異或值是0,且所有數都小於2,則先手敗,如果異或值是1,且所有數都是1,也是先手敗。其他情況都是先手勝。
代碼實現:
#include<bits/stdc++.h>
using namespace std;
int a[11111];
int main()
{
int n;
while(scanf("%d", &n) != EOF) {
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
int ans = 0;
int fa = 0;
for(int i = 1; i <= n; i++) {
ans ^= a[i];
if(a[i] > 1) fa = 1;
}
if(ans == 0 && fa == 0 || ans != 0 && fa == 1) {
cout << "先手敗" << endl;
}
else {
cout << "後手敗" << endl;
}
}
return 0;
}