//捡石子如果不是Nim就是一般的找规律,简单一些的手撕即可,但是有些,比如这个,就需要先手撕,然后打个表看看规律了。一般都不会很难
#include <cstdio>
#include <cstring>
const int MAX = 100;
int a[MAX][MAX]; //a[i][j]默认为0,表示如果有i个石子Alice第一次取j个为输,a[i][j]=1则表示第一次取j个可以必胜
int main() {
memset(a, 0, sizeof(a));
a[4][1] = 1;
a[6][1] = 1;
a[7][2] = 1;//先手撕出前7个的规律
//然后打表看剩下的
for (int i = 8; i < MAX; ++i) {
//比如有i个,我们知道如果第一次拿了超过i/3向上取整个,那么Bob肯定可以直接拿完,所以只考虑少于i/3向上取整个的
for (int j = 1; 3*j < i; ++j) {
//Alice拿j个,剩下i-j个
bool ok = false; //标记是否是一个必胜的策略
for (int k = 1; k <= 2*j; ++k) {
//Alice拿了j个,Bob可以拿[1,2*j]个
//我们知道,此时就相当于Bob是先手拿k个,如果a[i-j][k]为1,表示对i-j个石子拿掉k个可以保证自己赢
if (a[i-j][k]) {
ok = true;//说明Bob可以达到这个"必胜态"
break;
}
}
if (!ok) a[i][j] = 1;//如果Bob经过上面从1到2*j的尝试都无法找到一个必胜的策略,说明Bob是必败的,也就说明Alice必胜了
}
}
for (int i = 1; i < MAX; ++i) {
for (int j = 1; j < MAX; ++j) {
a[i][0] += a[i][j];
}
if (a[i][0] != 0) printf("%d\n", i); //看一下哪些是Alice的"必败"态
}
//可以发现,Alice的必败态是一个斐波那契数列
return 0;
}
然后就可以搞一个斐波那契数列了。
#include <cstdio>
#include <map>
using namespace std;
int main() {
map<int, bool> hs; //map标记一下
int a = 1, b = 2, c = 3;
hs[a] = hs[b] = true;
//这里利用整数的自然溢出的特点来处理循环终点,当然可以直接用long long代替
while (c > 0) {
hs[c] = true;
a = b;
b = c;
c += a;
}
int T, n;
scanf(" %d", &T);
while (T--) {
scanf(" %d", &n);
puts(hs.count(n) ? "Alice!" : "Bob!"); //http://www.cplusplus.com/reference/map/map/count/ 用find也可
}
return 0;
}