题目描述
有一个取数的游戏。初始时,给出一个环,环上的每条边上都有一个非负整数。这些整数中至少有一个0。然后,将一枚硬币放在环上的一个节点上。两个玩家就是以这个放硬币的节点为起点开始这个游戏,两人轮流取数,取数的规则如下:
(1)选择硬币左边或者右边的一条边,并且边上的数非0;
(2)将这条边上的数减至任意一个非负整数(至少要有所减小);
(3)将硬币移至边的另一端。
如果轮到一个玩家走,这时硬币左右两边的边上的数值都是0,那么这个玩家就输了。
如下图,描述的是Alice和Bob两人的对弈过程,其中黑色节点表示硬币所在节点。结果图(d)中,轮到Bob走时,硬币两边的边上都是0,所以Alcie获胜。
(a)Alice (b)Bob (c)Alice (d)Bob
现在,你的任务就是根据给出的环、边上的数值以及起点(硬币所在位置),判断先走方是否有必胜的策略。
输入格式:
第一行一个整数N(N≤20),表示环上的节点数。
第二行N个数,数值不超过30,依次表示N条边上的数值。硬币的起始位置在第一条边与最后一条边之间的节点上。
输出格式:
仅一行。若存在必胜策略,则输出“YES”,否则输出“NO”。
Analysis
第一眼看过去毫无想法
第二眼也是
第三眼也是
于是我就可耻地看了一发题解,博弈什么的果然很难
首先,对于一条链a1,a2,a3,a4……0 如果是偶数条边,那么现手一定赢,因为他每一次都只用把后面一条取完,例如
5 4 3 6 5 0
先手取完5,后手没法回到前一个位置,而无论接下来后手去多少,先手继续取完3,再然后取完5,后手没办法再去,先手赢。就这样,如果从起点到第一个出现0的地方一共有偶数条边,先手可以一步一步将后手被迫向前逼近,直到无法移动(由于是环,还应该考虑向后逼近)。
同样的,如果这有奇数个,那么先手第一步无论怎么取,都将自己置于一个必败状态(此时对于后手来说边数变成偶数),就一定没有必胜状态
也就是说对于固定的状态结果也是固定的
感受到nim游戏的高大上深奥了
下次遇到这种题能做出来吧?
Code
#include <stdio.h>
#include <string.h>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define fill(x, t) memset(x, t, sizeof(x))
#define N 41
using namespace std;
int num[N];
inline int read(){
int x = 0, v = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-'){
v = -1;
}
ch = getchar();
}
while (ch <= '9' && ch >= '0'){
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return x * v;
}
int main(void){
int n = read();
rep(i, 1, n){
num[i] = read();
}
rep(i, 1, n){
if (!num[i]){
if (i % 2 == 0){
printf("YES\n");
return 0;
}
break;
}
}
drp(i, n, 1){
if (!num[i]){
if ((n - i + 1) % 2 == 0){
printf("YES\n");
return 0;
}
break;
}
}
printf("NO\n");
return 0;
}