取数游戏

有一个有趣得取数游戏。初始时,给出一个环,环上得每条边上都有一个非负整数。这些整数中至少有一个是0。然后,将一枚硬币放在环上得一个节点上。二个玩家就是以这个放硬币得节点为起点开始这个游戏,二人轮流取数,取数得规则如下:

    (1)选择硬币左边或右边得一条边,并且边上得数非0;

    (2)将这条边上的数减至任意一个非负整数(至少要有所减小);

    (3)将硬币移到边的另一端。

    如果轮到一个玩家走,这时硬币左右两边的边上的数值都是0,那么这个玩家就输了。

    如下图所示,描述的时爱丽思和鲍勃两人的对弈过程,其中黑色节点表示硬币所在节点,结果图(d)中,轮到鲍勃走时,硬币两边的边上都是0。所以爱丽思获胜。

 

    现在你的任务是根据给出的环、边上的数值以及起点(硬币所在位置),判断先走方是否有必胜的策略。

    输入:第行一个整数N(N<=20),表示环上的节点数。

    第2行N个数,数值不超过30,依次表示N条边上的数值。硬币的起始位置是第一条边与最后一条边之间的节点上。

    输出:仅1行。若存在必胜策略,则输出‘YES’,否则输出‘NO’。

【输入输出样例】

cycle.in

4

2  5  3  0

cycle.out

YES

 

Cycle.in

3

0  0  0

cycle.out

NO

 

【问题分析】

    考虑一个简化的问题。如果硬币的一边的数值为0,那么惟一可能取胜的走法就是向另一边移动,并且把边上的数减到0。因为如果不把边上的数减到0,那么下一步对方会将硬币移动到原来的位置,并且将边上的数减到0,这样硬币两边的数值就都为0了。所以,对于一边有0的情况,双方惟一的走法就是不停的向另一边移动,并取完边上的数值。因此,判断是否有必胜策略,就是看另一个方向上连续的非零边是否为奇数条。

    那么两边都非零的情况呢?如果有一个方向上连续的非零边为奇数条,那么显然是有必胜策略的,因为只需往这个方向走并取完边上的数即可。如果两个方向上连续的非零边都是偶数条,则没有必胜策略。因为不管往哪个方向走,必然不能取完边上的数,否则必败。如果不取完,则下一步对方可以将硬币移动回原来的位置并取完边上的数,这样就变成了一边为0、另一边有偶数条连续的非零边的情况,还是必败。所以,对于一般的情况,只需判断硬币的两边是否至少有一边存在奇数条连续的非零边。如果存在,则有必胜策略;否则无必胜策略。算法的时间复杂度为O(N)。

【参考程序】

View Code
var i,n,left,right:longint;//left表示左边有几个连续非零数,right表示右边有几个连续非零数

a:array[1..20]of longint;

begin

readln(n);

for i:=1 to n do

read(a[i]);

left:=0;

right:=0;

for i:=1 to n do

if a[i]<>0 then inc(right)

else break;

for i:=n downto 1 do

if a[i]<>0 then inc(left)

else break;

if odd(left) or odd(right) then writeln('YES')//有必胜策略

else if (not odd(left))and(not odd(right)) then writeln('NO');//无必胜策略

end.

posted on 2011-10-25 19:16  kid_jiao  阅读(352)  评论(0)    收藏  举报

导航