题目链接: link.
原题:山上住着一只金刚狼与一只小狗灰,它们都认为一直以来是自己独享整座山,直到有一天它们相遇,它们都感到自己的领地受到了侵犯,互不相让,一场精彩狼狗大战即将上演,但是它们突然想起现在早已进入了文明社会,它们不能再用拳脚争斗了,看来今天只能通过智力一决高低,来决定谁才是这座山的拥有者,谁才是真正的犬科之王,比赛是这样的,它们都有一个可以容纳橙子的袋子,这两个袋子是由一位数学大师制作而成,容量大小被神奇的设置成了第N个素数,现在有一堆总数为M的橙子,从金刚狼开始轮流用袋子把橙子运到自己的家里,每次取的橙子数是任意的但不能为零,也不能超出袋子的容量,最后橙子被取完了不能拿的为败者,它们两个都采取最优策略,谁会取胜呢?
输入
首先输入两个正整数 N,M(1<N<1000,1e5
如果金刚狼取胜输出JGL666 如果小狗灰取胜输出XGH666
样例1
输入
1 999999
输出
XGH666
博弈论
一.巴什博弈。(同余理论)
只有一堆n个物品,两个人轮流从中取物,规定每次最少取一个,最多取m个,最后取光者为胜。
if(n%(m+1)==0) cout<<"后手必胜"<<endl;
else cout<<"先手必胜"<<endl;
二。威佐夫博弈。(黄金分割)
有两堆各若干的物品,两人轮流从其中一堆取至少一件物品,至多不限,或从两堆中同时取相同件物品,规定最后取完者胜利。
解题核心就是:看两个数的差值t是不是满足 (sqrt(5)+1)/2*t==min(n1,n2);
#include
#include
#include
using namespace std;
int main()
{
int n1,n2,temp;
while(cin>>n1>>n2)
{
if(n1>n2) swap(n1,n2);
temp=floor((n2-n1)*(1+sqrt(5.0))/2.0);
if(temp==n1) cout<<"后手必胜"<<endl;
else cout<<"先手必胜"<<endl;
}
return 0;
}
三。尼姆博弈。(异或理论)
有任意堆物品,每堆物品的个数是任意的,双方轮流从中取物品,每一次只能从一堆物品中取部分或全部物品,最少取一件,取到最后一件物品的人获胜。
解题核心:把每堆物品数全部异或起来,如果得到的值为0,那么先手必败,否则先手必胜。
#include
#include
#include
using namespace std;
int main()
{
int n,ans,temp;
while(cin>>n)
{
temp=0;
for(int i=0;i<n;i++)
{
cin>>ans;
temp^=ans;
}
if(temp==0) cout<<"后手必胜"<<endl;
else cout<<"先手必胜"<<endl;
}
return 0;
}
四。斐波那契博弈。
有一堆物品,两人轮流取物品,先手最少取一个,至多无上限,但不能把物品取完,之后每次取的物品数不能超过上一次取的物品数的二倍且至少为一件,取走最后一件物品的人获胜。
解题核心:先手胜当且仅当n不是斐波那契数(n为物品总数)
#include
#include
#include
using namespace std;
const int N = 55;
int f[N];
int main()
{
f[0] = f[1] = 1;
for(int i=2;i<N;i++)
f[i] = f[i-1] + f[i-2]
int n;
while(cin>>n)
{
if(n == 0) break;
bool flag = 0;
for(int i=0;i<N;i++)
{
if(f[i] == n)
{
flag = 1;
break;
}
}
if(flag) puts("Second win");
else puts("First win");
}
return 0;
}
五。环形博弈。
n个石子围成一个环,每次取一个或者取相邻的2个。
解题核心:石子数目小于等于2 先手胜,其他 后手胜。
六。对称博弈。
对称博弈
n个石子围成环,每次只能取相邻的1 - k个
①如果k < n:
对k=1,如果n能被2整除,则后手赢
如果k>1,后手赢(先手取什么位置后手就取对称的位置,这样保证后手永远能取到)
② 如果k>=n:
先手赢.
该题很明显是一堆物品,每次最多取第n个素数个,显然是第一种博弈论。
#include
using namespace std;
bool prime(int x)
{
if(x<2) return false;
else{
for(int i=2;i<=x/i;i++)
{
if(x%i==0) return false;
}
}
return true;
}
int main()
{
int n,m;
cin>>n>>m;
int sum=0,t;
for(int i=1;;i++)
{
if(prime(i)) sum++;
if(sum==n)
{
t=i;
break;
}
}
if(m%(t+1)==0) cout<<"XGH666"<<endl;//博弈论
else cout<<"JGL666"<<endl;
return 0;
}