P1288 取数游戏II
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1288 取数游戏II相关的知识,希望对你有一定的参考价值。
题意:
一个环,由边权,硬币一开始在一个点上,两个人轮流操作,每次操作向左或右移动,每次移动必须将边权减少到非负整数,如果原本是0则不能走,当不能走动时,该方输掉比赛
问先手是否右必胜策略
题目保证至少有个边为0
题解:
构造SG函数:当前节点和0边之间的边数%2,奇数边sg=1为必胜局面,偶数条边sg=0为必败局面
- 终局为必败局面
- 必胜可以走到必败局面,奇->偶
- 必败不能到必败局面,无法奇->奇
有奇数条边则必胜,否则必败;
怎么理解:
对于一条链(环的问题一般都要链化),a1,a2,a3…0,如果到是偶数个边(末尾为0),那么先手一定赢,因为先手可以将a1剪成0,后手无法返回,只能继续走,不管后手怎么走,先手都可以再将a3减成0到达a4,因为是偶数个边,随意最后后手正好被卡在两个0之间,输掉游戏
反过来,如果是奇数个,先后不管怎么走,先走一部后,对于后手,还有偶数个边可以走,按照上面讲的,后手必胜
注意题目是个环,所以还要顺逆时针两个方向看
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,a[25];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",a+i);
for(int i=1;i<=n;i++)//顺时针看
if(a[i]==0){
//如果到0有偶数个边,先手必胜
if(i%2==0)return puts("YES"),0;
break;
}
for(int i=n;i>=1;i--)//逆时针看
if(a[i]==0){
//
if((n-i+1)%2==0)return puts("YES"),0;
break;
}
puts("NO");
return 0;
}
以上是关于P1288 取数游戏II的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode810. 黑板异或游戏/455. 分发饼干/剑指Offer 53 - I. 在排序数组中查找数字 I/53 - II. 0~n-1中缺失的数字/54. 二叉搜索树的第k大节点(代码片段