高僧斗法

这个题目是一个nim游戏的变种

题意是:

古时丧葬活动中经常请高僧做法事。仪式结束后,有时会有“高僧斗法”的趣味节目,以舒缓压抑的气氛。
节目大略步骤为:先用粮食(一般是稻米)在地上“画”出若干级台阶(表示N级浮屠)。又有若干小和尚随机地“站”在某个台阶上。最高一级台阶必须站人,其它任意。(如图1所示)
两位参加游戏的法师分别指挥某个小和尚向上走任意多级的台阶,但会被站在高级台阶上的小和尚阻挡,不能越过。两个小和尚也不能站在同一台阶,也不能向低级台阶移动。
两法师轮流发出指令,最后所有小和尚必然会都挤在高段台阶,再也不能向上移动。轮到哪个法师指挥时无法继续移动,则游戏结束,该法师认输。
对于已知的台阶数和小和尚的分布位置,请你计算先发指令的法师该如何决策才能保证胜出。

思路:

首先想到的是搜索,就是枚举每次可行的走法,来判断是不是必败态

但是暴力做法会超时的,然后我们可以这么抽象,把相邻的和尚距离看作一堆石子,为什么可以这么看呢?其实就是一层抽象,对于对方走的某个和尚的步数,我们可以跟随与他相邻的和尚的步数来保证当前状态的不变性,直到某一个和尚到达顶峰,这时就对这个区间抽象为某一堆石子,这时就变成了nim游戏。

过程有点抽象,但是仔细想一下确实最终变成k堆石子的nim游戏

代码:

其中dfs为搜索(超时了) 

check中为nim游戏(0ms通过)

nim游戏的结论是:每一堆石子的异或和为0那么这个状态就是必败态

#include <iostream>
#include <vector>
#include <map>
using namespace std;

vector<int> st;
vector<int> _end;

map<vector<int>,int> mp;


bool dfs(vector<int>& now){
    if(now==_end)return false;
    if(mp[now]!=0)return mp[now]==1;
    for(int i=0;i<now.size()-1;i++){
        int dta=now[i+1]-now[i]-1;
        if(dta==0)continue;
        for(int k=1;k<=dta;k++){
            now[i]+=k;
            if(!dfs(now)){
                now[i]-=k;
                mp[now]=1;
                return true;
            }
            now[i]-=k;
        }
    }
    mp[now]=-1;
    return false;
}
bool check(vector<int> s){
    int ans=0;
    for(int i=0;i<s.size()-1;i+=2){
        ans^=(s[i+1]-s[i]-1);
    }
    return ans==0;
}

//我们可以通过跟随下一个人的走法保持对面必败的局面,或者是移动其他堆的和尚来保持对手处于必败局面
//可以这么理解,如果是选择跟随的话相当于一回合延续了好久,就是到了最后才不得不变成一堆,然后各自取(这样就抽象为nim游戏了)

int main(){
    int pos;
    mp.clear();
    st.clear();
    _end.clear();
    while(cin>>pos){
        st.push_back(pos);
    }
    int n=st.size();
    int maxpos=st.back();
    int estpos=maxpos-n+1;
    while(estpos<=maxpos){
        _end.push_back(estpos);
        estpos++;
    }
    if(st==_end){
        cout<<-1<<" "<<-1<<endl;
        return 0;
    }
    // int ans=0;
    for(int i=0;i<n-1;i++){
        int dta=st[i+1]-st[i]-1;
        if(dta==0)continue;
        for(int k=1;k<=dta;k++){
            st[i]+=k;
            if(check(st)){
                cout<<st[i]-k<<" "<<st[i]<<endl;
                return 0;
            }
            st[i]-=k;
        }
    }
    cout<<-1<<" "<<-1<<endl;
    return 0;
}

 

posted @ 2020-07-26 23:30  kstranger  阅读(171)  评论(0)    收藏  举报