取数游戏II-洛谷


题目描述

image-20220215111503362

image-20220215111527507


解题思路

  1. 问题简化

由题目知,这个环里至少有一条边为0,而为0的边是无法经过的,所以起点两边的两个第一个为0的边之间的边是不可能到达的,因此可以把问题简化为只有1个边为0的环,即把那些不可能到达的边删除并把两个为0的边仅保留1个,如下图

image-20220215135253100

之后再更新一下n,如上图即n由7更新为5。

  1. 存在必胜策略反推

当轮到对手时硬币两边的边上都是0,那我们就赢了。

image-20220215135933945

则如果轮到我们的时候硬币与长度为0的边中间恰好隔着1条非0边,就有必胜策略。(结论1)

image-20220215140009209

当硬币的一条临边为0时,则在往另一临边移动后必须把该临边减为0,否则对手就可以直接往回走并把该临边减为0,那我们就输定了。

所以,当硬币的一条临边为0时,则最优策略为往另一临边移动并把该临边减为0。(结论2)

image-20220215140827592

由结论1和结论2可以推出,

只要起点往顺时针方向或逆时针方向与长度为0的边之间的边数为奇数,则存在必胜策略。(结论3)

当更新后的n为偶数时,即非0边数为奇数,则必有一个方向满足与长度为0的边之间的边数为奇数,再由结论3可以推出,

若更新后的n为偶数,则存在必胜策略。(结论4)

当更新后的n为奇数时,即非0边数为偶数,则 两个方向均与长度为0的边之间的边数为奇数 或 两个方向均与长度为0的边之间的边数为偶数 ,则只需要考虑其中一个方向即可,再由结论3可以推出,

若0边对应存储的数组下标为奇数,则存在必胜策略,反之则不存在。(结论5)

代码

#include <iostream>
using namespace std;
int a[20];
int main(){
    int n, first0ind, last0ind, m;
    cin >> n;
    // 输入同时标记首0元素下标
    for (int i = 0; i < n; i++){
        cin >> a[i];
        if (!a[i]){
            first0ind = last0ind = i;
            m = i + 1;
            break;
        }
    }
    // 输入同时标记末0元素下标
    for (int i = m; i < n; i++){
        cin >> a[i];
        if (!a[i])	last0ind = i;
    }
    // 简化问题为只有1边为0
    if (first0ind != last0ind)
        for (int i = 1; i + last0ind < n; i++)
            a[first0ind + i] = a[last0ind + i];
    // 新的长度
    n += first0ind - last0ind;
    // 解答
    if (n % 2 == 0){
        // n为偶数先手存在必胜策略
        cout << "YES" << endl;
    }
    else{
        // 唯一0元素的下标为奇数则先手存在必胜策略,为偶数则先手不存在必胜策略
        if (first0ind % 2)	cout << "YES" << endl;
        else	cout << "NO" << endl;
    }
    return 0;
}

image-20220215143341590

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值