转化问题为Nim博弈

Nim博弈

给出n堆石子,每堆有若干个石子,每次可以向任意堆石子中取任意多个石子,谁最后不能取石子谁输。

结论:将每堆石子数作异或和

若异或和为0,先手必败。

若异或和不为0,先手必胜。

 

http://acm.hdu.edu.cn/showproblem.php?pid=4315

大意:按编号大小顺序给出n个人的位置编号,山顶的编号是0,国王的位置编号是第k个人的位置编号,每次可以将一个人从当前位置向左移向任意位置,但不能超越左边的人,也不能两个人占用同一个人的位置。谁先把国王移动到山顶谁就赢。

思路:这题并不能直接看出是Nim博弈。依据题意可知,每个人移动的范围是当前位置和左边第一个人位置之间的位置。其实这之前的位置就可以看成是一堆石子,为什么这样说呢?假设左右两个人的分别是a,b,如果此时就是必胜态,下一次如果将a向左移动,那么下下次就将b向左移动相同的距离,此时还是必胜态,如果将b向左移动,不就相当于在这一堆石子里面取走石子吗?所有将两两之间的空位置作为一堆石子,然后就按照nim博弈的做法去做就行。当n为奇数时,我们将最终位置和第一个人的位置组成一队。

注意:因为这题是要将国王移到0就赢,所有如果k=1,先手直接将国王移到0,所有必胜。如果k=2,并且n为奇数,此时谁都不想将国王前面那个人移到0,因为这样的话,下一个人一定可以将国王直接移到0,所以次数第一个人要和1组队,而不是0.

Code


#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const ll mod = 1e9+7;
const int N = 2e6+7;
const ll ds = 1e15+7;
const double PI = 3.141592653589793238462643383;
 
using namespace std;

int a[N];
void solve(){
    int n,k;
    while(cin >> n >> k){
        for(int i = 1; i <= n; i++){
            cin >> a[i];
        }
        if(k == 1) {
            cout << "Alice\n";
            continue;
        }
        int ans = 0,tmp;
        if(n&1){
            ans = a[1];
            if(k == 2) ans--;
            for(int i = 2; i < n; i++){
                tmp = (a[i+1]-a[i]-1);
                ans ^= tmp;
            }
        }
        else{
            for(int i = 1; i < n; i += 2){
                tmp = (a[i+1]-a[i]-1);
                ans ^= tmp;
            }
        }
        if(ans) cout << "Alice\n";
        else cout << "Bob\n";
    }
}

int main(){
    // int t;
    // cin >> t;
    // while(t--)
        solve();
    //system("pause");
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值