斐波那契博弈
有一堆個數爲n(n>=2)的石子,遊戲雙方輪流取石子,規則如下:
1)先手不能在第一次把所有的石子取完,至少取1顆;
2)之後每次可以取的石子數至少爲1,至多爲對手剛取的石子數的2倍。
約定取走最後一個石子的人爲贏家,求必敗態。
結論:當n爲Fibonacci數的時爲必敗態。
即將斐波那契數列打表再判斷n是否爲斐波那契數判斷即可
例題:HDU - 2516 取石子游戲
(我這裏打表了,TIME是0 哦豁)
#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
long long feibonaq[100]={
1,
2,
3,
5,
8,
13,
21,
34,
55,
89,
144,
233,
377,
610,
987,
1597,
2584,
4181,
6765,
10946,
17711,
28657,
46368,
75025,
121393,
196418,
317811,
514229,
832040,
1346269,
2178309,
3524578,
5702887,
9227465,
14930352,
24157817,
39088169,
63245986,
102334155,
165580141,
267914296,
433494437,
701408733,
1134903170,
1836311903,
2971215073,
4807526976,
7778742049,
12586269025,
20365011074,
32951280099,
53316291173,
86267571272,
139583862445,
225851433717,
365435296162,
591286729879,
956722026041,
1548008755920,
2504730781961,
4052739537881,
6557470319842,
10610209857723,
17167680177565,
27777890035288,
44945570212853,
72723460248141,
117669030460994,
190392490709135,
308061521170129,
498454011879264,
806515533049393,
1304969544928657,
2111485077978050,
3416454622906707,
5527939700884757,
8944394323791464,
14472334024676221,
23416728348467685,
37889062373143906,
61305790721611591,
99194853094755497,
160500643816367088,
259695496911122585,
420196140727489673,
679891637638612258,
1100087778366101931,
1779979416004714189,
2880067194370816120,
4660046610375530309,
7540113804746346429};
int main() {
ios::sync_with_stdio(false);
ll n;
while(~scanf("%lld",&n)) {
if(n==0) break;
int flag=0;
if(n<=2971215073) {
for(int i=1;i<=45;i++) {
if(n<feibonaq[i]) break;
if(n==feibonaq[i]) {
flag++;
break;
}
}
}
else {
for(int i=46;i<=90;i++) {
if(n<feibonaq[i]) break;
if(n==feibonaq[i]) {
flag++;
break;
}
}
}
if(flag==1) printf("%s\n","Second win");
else printf("%s\n","First win");
}
return 0;
}
巴什博弈
只有一堆n個物品,兩個人輪流從中取物,規定每次最少取一個,最多取m個,最後取光者爲勝。
結論:一輪最多拿的就是1+m個,所以控制下去,最後的不到(1+m)的物品肯定會被後手拿到的。
即判斷n能不能除盡m+1,如若能則後手必勝
例題:HDU - 1846 Brave Game
#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
//如果m+1>=n,則後手必勝,說明當是這種情況的倍數時,後手能夠一直製作出這種情況,則後手必勝
if(n%(m+1)==0) cout<<"second"<<endl;
else cout<<"first"<<endl;
}
return 0;
}
尼姆博弈
有任意堆物品,每堆物品的個數是任意的,雙方輪流從中取物品,每一次只能從一堆物品中取部分或全部物品,最少取一件,取到最後一件物品的人獲勝。
結論:把每堆物品數全部異或起來,如果得到的值爲0,那麼先手必敗,否則先手必勝。
例題:POJ - 2234 Matches Game
#include <iostream>
//#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int k[100];
int main() {
ios::sync_with_stdio(false);
int n;
while(cin>>n) {
int tmp=0;
for(int i=0;i<n;i++) {
cin>>k[i];
tmp^=k[i];
}
if(tmp==0) cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
}
乘法博弈
2 個人玩遊戲,從 1 開始,輪流對數進行累乘,直到超過一個指定的值m時,該玩家獲勝。
如果乘數範圍是2~n,
則如果m爲2~n,則先手必勝。
如果是n+1~2×(上一個後範圍),則後手必勝,因爲無論第一次先手乘的數是什麼,數必在2到n之間
結論:必勝態對稱,於是將m不斷除與2n,判斷餘數在2到n還是n+1到2n之間即可
例題:POJ - 2505 A multiplication game
#include <iostream>
//#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
long double n;
while(cin>>n) {
while(n>18) {
n/=2;
n/=9;
}
if(n<=9) cout<<"Stan wins."<<endl;
else cout<<"Ollie wins."<<endl;
}
}
環形博弈
n個石子圍成一個環,每次取一個或者取相鄰的2個。
證明:以後再寫(
結論:石子數目小於等於2 先手勝,其他 後手勝。
例題:POJ - 2484 A Funny Game
#include <iostream>
//#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
int n;
while(cin>>n&&n!=0) {
if(n<=2) cout<<"Alice"<<endl;
else cout<<"Bob"<<endl;
}
}
對稱博弈
n個石子圍成環,每次只能取相鄰的1 - k個
結論:如果k<n:對k=1,如果n能被2整除,則後手贏
如果k>1,後手贏(先手取什麼位置後手就取對稱的位置,這樣保證後手永遠能取到)
如果k>=n:先手贏
例題:HDU - 3951 Coin Game
#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
int t;
cin>>t;
for(int i=1;i<=t;i++) {
int n,k;
cin>>n>>k;
cout<<"Case "<<i<<": ";
if(k<n) {
if(k==1) {
if(n%2==0) cout<<"second"<<endl;
else cout<<"first"<<endl;
}
else cout<<"second"<<endl;
}
else cout<<"first"<<endl;
}
}
威佐夫博弈
有兩堆各若干的物品,兩人輪流從其中一堆取至少一件物品,至多不限,或從兩堆中同時取相同件物品,規定最後取完者勝利。
結論:看兩個數的差值t是不是滿足 (sqrt(5)+1)/2*t==min(n1,n2);,是的話則後手必勝
例題:HDU - 1527 取石子游戲
#include <bits/stdc++.h>
#define endl '\n'
#define INF 1e9+7
#define ll long long
#define ull unsigned long long
using namespace std;
int main() {
ios::sync_with_stdio(false);
int a,b;
double temp;
while(cin>>a>>b) {
if(a>b) swap(a,b);
temp=floor((b-a)*(1+sqrt(5.0))/2.0);
if(temp==a) cout<<0<<endl;
else cout<<1<<endl;
}
}