[蓝桥杯 2013 国 B] 高僧斗法(台阶Nim)

[蓝桥杯 2013 国 B] 高僧斗法

题目描述

古时丧葬活动中经常请高僧做法事。仪式结束后,有时会有“高僧斗法”的趣味节目,以舒缓压抑的气氛。

节目大略步骤为:先用粮食(一般是稻米)在地上“画”出若干级台阶(表示 N N N 级浮屠)。又有若干小和尚随机地“站”在某个台阶上。最高一级台阶必须站人,其它任意。(如图 1 1 1 所示 )。

两位参加游戏的法师分别指挥某个小和尚向上走任意多级的台阶,但会被站在高级台阶上的小和尚阻挡,不能越过。两个小和尚也不能站在同一台阶,也不能向低级台阶移动。

两法师轮流发出指令,最后所有小和尚必然会都挤在高段台阶,再也不能向上移动。轮到哪个法师指挥时无法继续移动,则游戏结束,该法师认输。

对于已知的台阶数和小和尚的分布位置,请你计算先发指令的法师该如何决策才能保证胜出。

输入格式

输入数据为一行用空格分开的 N N N 个整数,表示小和尚的位置。台阶序号从 1 1 1 算起,所以最后一个小和尚的位置即是台阶的总数。( N < 100 , N<100, N<100, 台阶总数 < 1000 <1000 <1000

输出格式

输出为一行用空格分开的两个整数 : A , B A,B A,B, 表示把 A A A 位置的小和尚移动到 B B B 位置。若有多个解,输出 A A A 值较小的解,若无解则输出 − 1 -1 1

样例 #1

样例输入 #1

1 5 9

样例输出 #1

1 4

样例 #2

样例输入 #2

1 5 8 10

样例输出 #2

1 3

提示

时限 1 秒, 64M。蓝桥杯 2013 年第四届国赛

思路

请添加图片描述
首先我们得知道Nim游戏:(注意上面出现的红体字,其中的第 k 位指的是如上右图的 s 0101 我们去找上面的数字谁的第3位是1,我们发现是7,那么我们就让7^s去替换7,得到的结果是 0 ,说明对于必胜态,它的后继节点至少存在一个是必败态(因为你可能不是替换7))。

然后我们延申到台阶的。请添加图片描述
上图为台阶型。

请添加图片描述
上图圈圈的是看成每个台阶上的石子。

因此这道题就是很典型的台阶性Nim游戏,只不过它求的是方案。哎,方案,还要字典序最小,你就从小到大枚举就行了呀。然后看看每次枚举后是否符合先手必胜。

代码(附详细讲解)

//这道题就是Nim游戏(台阶型)求方案的问题

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1010;

int n;
int w[N];
int tot;
int b[N];//相邻台阶数——此时相当于每组的石子数

bool Nim(){
    
    int res=0;
    
    for(int i=0;i<n;i+=2){//每两个和尚组成一堆,所以每两个一组
        res^=b[i];
    }
    
    // if(res==0)return true;//先手必败
    // return false;//先手必胜
    return res==0;
}

int main(){
    
    while(cin>>w[n])n++;
    
    //这边就得统计每组的石子数啦
    
    for(int i=0;i<n-1;i++){
        b[i]=w[i+1]-w[i]-1;
    }
    n--;//最后一个小和尚没什么用,直接删掉
    if(Nim())puts("-1");
    else{
        //其实记录方案数就是每移动一次看是否满足条件
        for(int i=0;i<n;i++){
            for(int j=1;w[i]+j<w[i+1];j++){//枚举每级台阶
                b[i]-=j;
                if(i)b[i-1]+=j;//w[i]向上走了j级,那 b[i-1] 
                //则要增加 j 级,如果动的是w[1],由于他下面没有小和尚了,所以不用改;
                if(Nim()){
                    cout<<w[i]<<' '<<w[i]+j<<endl;
                    break;
                }
                b[i]+=j;
                if(i)b[i-1]-=j;
            }
        }
    }
    
    return 0;
    
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值