有一个有趣得取数游戏。初始时,给出一个环,环上得每条边上都有一个非负整数。这些整数中至少有一个时0。然后,将一枚硬币放在环上得一个节点上。二个玩家就是以这个放硬币得节点为起点开始这个游戏,二人轮流取数,取数得规则如下:
(1)选择硬币左边或右边得一条边,并且边上得数非0;
(2)将这条边上的数减至任意一个非负整数(至少要有所减小);
(3)将硬币移到边的另一端。
如果轮到一个玩家走,这时硬币左右两边的边上的数值都是0,那么这个玩家就输了。
如下图所示,描述的时爱丽思和鲍勃两人的对弈过程,其中黑色节点表示硬币所在节点,结果图(d)中,轮到鲍勃走时,硬币两边的边上都是0。所以爱丽思获胜。
现在你的任务是根据给出的环、边上的数值以及起点(硬币所在位置),判断先走方是否有必胜的策略。
输入:第行一个整数N(N<=20),表示环上的节点数。
第2行N个数,数值不超过30,依次表示N条边上的数值。硬币的起始位置是第一条边与最后一条边之间的节点上。
输出:仅1行。若存在必胜策略,则输出‘YES’,否则输出‘NO’。
样例1:
4
2 5 3 0
样例2:
3
0 0 0
样例1:
YES
样例2:
NO
如描述
题目思路
这个题根本就不是WIKI上标的DP题,而是一道纯粹的模拟题,根据输入数据特点,需要断环为链,再求解,断环为链过程如下图所示
可以使用两个数组linea lineb保存顺时针、逆时针方向的两种反方向的链(如下面代码所示),也可以只用一个数组保存,数组的中点就是出发点,从顺时针、逆时针两个方向寻找答案。
然后就是求解了,要想第一个赢,就得以奇数步到达其中一个边权为0的点(想一想,为什么),由于是第一个玩这个游戏,硬币走奇数步到这个点的人才是自己,而对手要走偶数步,而根据题意可以看出,要想使硬币的两边边权都为0,就必须让硬币到达只有一边边权为0的点,再对另一边边权清零,又为了在最短步数内到达这样一个点,硬币应该始终沿同一方向移动(每次减少与运动方向相反的边的边权)。
下面是代码
#include <stdio.h> int n,linea[50],lineb[50]; //linea、lineb=保存环的数组 int main() { int i,j,k,stepa=0,stepb=0; //stepa=逆时针走的步数,stepb=顺时针走的步数 scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&linea[i]);//读入环 for(i=n;i>=1;i--) lineb[n-i+1]=linea[i];//断环为链 for(i=1;i<=n;i++) { if(linea[i]==0) break; stepa++; } for(i=1;i<=n;i++) { if(lineb[i]==0) break; stepb++; } if(stepa%2==1||stepb%2==1) printf("YES\n"); else printf("NO\n"); return 0; }