[Wikioi 1037]取数游戏

    有一个有趣得取数游戏。初始时,给出一个环,环上得每条边上都有一个非负整数。这些整数中至少有一个时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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值