对于这个35学分的学期,每周前三天的课还是很要命的,不知不觉到了周三,今天是开刷题的时间,计划到24号完成Lv.1,每人每天9道题左右,明天还是要多呆在实验室,关于博弈SG函数看的不好,还得继续看看.
Fibonacci博弈
问题模型:有一堆个数为n的石子,游戏双方轮流取石子,满足:
(1)先手不能在第一次把所有的石子取完;
(2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)。 约定取走最后一个石子的人为赢家。
解决方法:当n为Fibonacci数时,先手必败。即存在先手的必败态当且仅当石头个数为Fibonacci数。
之前在牛客网遇到过:https://www.nowcoder.com/acm/contest/77/G
代码为:
#include <bits/stdc++.h>
using namespace std;
const int N = 50;
int f[N];
void Init()
{
f[0] = f[1] = 1;
for(int i=2;i<N;i++)
f[i] = f[i-1] + f[i-2];
}
int main()
{
Init();
int n;
while(scanf("%d",&n)!=EOF)
{
if(n == 0) break;
bool flag = 0;
for(int i=0;i<N;i++)
{
if(f[i] == n)
{
flag = 1;
break;
}
}
if(flag) puts("Sha");
else puts("Xian");
}
return 0;
}
尼姆博弈
问题的基本模型为:有三堆各若干个物品(个数分别为a,b,c),两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。这里的三个一般可推广至n个、
解决思路:先手必败态等价于a^b^c=0(^表示异或运算)。
推广至n个物品:
#include<cstdio>
#include<cmath>
#include<iostream>
using namespacestd;
int main()
{
int n,ans,temp;
while(scanf(“%d”,&n)!=EOF)
{
temp=0;
for(int i=0;i<n;i++)
{
scanf("%d",&ans);
temp^=ans;
}
if(temp==0) cout<<"后手必胜"<<endl;
else cout<<"先手必胜"<<endl;
}
return 0;
}