蓝桥杯T37(nim博弈)

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T37

 

题意:中文题诶~

 

思路:nim博弈

个人感觉这题最难的地方是将题目转换为博弈模型,如果能将之转换为博弈模型的话题目也就迎刃而解啦;

本题的解法是将相邻的两个和尚之间的台阶数目看做一堆石头,那么就变成nim博弈啦,对于和尚数目为奇数的情况,直接将最后一个和尚忽略或者在最后那个和尚后面再加一个和尚即可,后者相当于加了一堆数目为0的石头,和前者没什么区别;

本题和一般nim博弈的不同之处是本题中石头的数目是可以增加的,其实就是将后面那个和尚往后移啦;如果直接按照博弈思路去求那个bi'的话得到的解可能不是最小的(在本题中最后一组数据会wa)。要得到最小解的话就需要我们枚举每一个和尚并分别判断石头增加和减少的情况啦。。

 

直接求bi'的代码:

 

 1 #include <iostream>
 2 #include <stdio.h>
 3 #define MAXN 110
 4 using namespace std;
 5 
 6 int a[MAXN], b[MAXN];
 7 
 8 int main(void){
 9     char ch;
10     int pos=0;
11     while(1){
12         scanf("%d%c", &a[pos++], &ch);
13         if(ch=='\n'){
14             break;
15         }
16     }
17     if(pos&1){
18         pos--;
19     }
20     for(int i=0; i<pos; i+=2){
21         b[i>>1]=a[i+1]-a[i]-1;
22     }
23     pos>>=1;
24     int ans=0;
25     for(int i=0; i<pos; i++){
26         ans^=b[i];
27     }
28     if(!ans){//面对奇异局势,必败
29         cout << -1 << endl;
30     }else{
31         for(int i=0; i<pos; i++){
32             if((ans^b[i])<b[i]){//找到bi'替换bi使变成奇异局势
33                 int cnt=ans^b[i];
34                 cout << a[i<<1] << " " << a[i<<1]+(b[i]-cnt) << endl;
35                 break;
36             }
37         }
38     }
39     return 0;
40 }
41 
42 // 1 4 8 12 16 19 28 33 35 36 40 45 52 66 67 68 69 77 85 99 102 134 155 211 214 216 355 376 400 412
43 // 134 148
View Code

 

 

枚举求解的代码:

#include <iostream>
#include <stdio.h>
#define MAXN 110
using namespace std;

int a[MAXN], b[MAXN];

int main(void){
    char ch;
    int pos=0;
    while(1){
        scanf("%d%c", &a[pos++], &ch);
        if(ch=='\n'){
            break;
        }
    }
    if(pos&1){
        pos--;
    }
    int len=pos;
    for(int i=0; i<pos; i+=2){
        b[i>>1]=a[i+1]-a[i]-1;
    }
    pos>>=1;
    int ans=0;
    for(int i=0; i<pos; i++){//面对奇异局势,必败
        ans^=b[i];
    }
    if(!ans){
        cout << -1 << endl;
    }else{
        for(int i=0; i<len; i++){//枚举每一个人移动的情况
            for(int j=a[i]+1; j<a[i+1]; j++){//当前和尚可以向前移动到前一个和尚下面一个台阶
                if(i&1){//若当前是第偶数个和尚,则相当于当前堆石头数目增加
                    int cnt=j-a[i-1]-1;
                    if(!(ans^cnt^b[i/2])){//移动后变成奇异局势
                        cout << a[i] << " " << j << endl;
                        return 0;
                    }
                }else{//当前是第奇数个和尚,则相当于当前堆石头数目减少
                    int cnt=a[i+1]-j-1;
                    if(!(ans^cnt^b[i/2])){//移动后变成奇异局势
                        cout << a[i] << " " << j << endl;
                        return 0;
                    }
                }
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2017-03-18 22:28  geloutingyu  阅读(225)  评论(0编辑  收藏  举报