取数游戏II_洛谷1288_博弈

来源:互联网 发布:麦迪职业生涯数据统计 编辑:程序博客网 时间:2024/06/14 12:57

题目描述


有一个取数的游戏。初始时,给出一个环,环上的每条边上都有一个非负整数。这些整数中至少有一个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 41using 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;}
1 0
原创粉丝点击