1704 Georgia and Bob(尼姆博弈变形)

解题思路:

有一列相连排列的网格,有N个走棋,每个走棋占一个网格,有空的网格。Georgia和Bob轮流玩游戏,每次游戏Georgia先玩。

游戏规则为:玩家每次选择一个走棋移动,只能向左移动,移动的网格数至少为1,但移动过程中不能覆盖或越过其他的走棋,切不能移出网格外。


如上图:第一个走棋已经在最左边的网格上了,就不能再往左移动了。如果玩家到最后不能移动走棋了,则为输。

解题思路:

从网上看来的解题思路,如果让我想的话肯定是想不出来的,毕竟不是大牛。

把走棋从右往左两两分为一组,如果走棋的个数为奇数,则最左边落单的走棋和最左边的网格的左边沿假象的一个走棋为一组。然后把每两组走棋之间的网格数当成一堆石头,转化为尼姆博弈,是不是很神奇呢!

证明模型的正确性:

1、首先明确的是:每次移动走棋,都是移动一组中左边或者右边的走棋。尼姆博弈就是在不断的变换异或和,即从0变为非0,再变为0的过程。

2、假设一组表示为(n,m)(n是左边走棋的坐标,m是右边走棋的坐标),当移动的走棋是一组左边的走棋,移动步数为x,变为(n-x,m),则可以移动右边走棋x步,变为(n-x,m-x),这就是异或和从0变为非0,再变为0的过程。

2、如果移动的是一组中右边的走棋x步,不能保证能够移动左边的走棋x步,所以按照(2)的移动方式是不可行的。但按照尼姆博弈的思想,移动一组中右边的走棋x步,相当于从一堆石头中取走x块石头,这是可以从另一堆石头中取走x块石头,使得异或和为0。所以对于移动走棋,这是将另一组的右边的走棋移动x步,使得异或和变为0.

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main(){
    int t,n;
    int pos[1005],num[1005];
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d",&pos[i]);
        sort(pos,pos+n); //题目中并没有说坐标是按由小到大的顺序给的,所以要对坐标排序
        int th=0;
        int i=0;
        if(n%2==1){
            num[th]=pos[i]-1;
            i++;th++;
        }
        for(int j=i;j<n-1;){

            num[th++]=pos[j+1]-pos[j]-1;
            j+=2;
        }
        int sum=0;
        for(int i=0;i<th;i++) sum=sum^num[i];
        if(sum==0) printf("Bob will win\n");
        else printf("Georgia will win\n");
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值