hdu 4315 Climbing the Hill 博弈问题,可转化为nim游戏问题,多校联合赛(二)第六题

博弈问题,先考虑如果总数n为偶数(k!=1),当n个点全两两挨在一起时,谁先走谁输(自己模拟吧)

当总数n为奇数时(k!=1),先吧第一个点走道终点,然后就是偶数的情况了,然后考虑怎么将他们两两挨在一起(注意不用所有点都挨在一起)

这是就是当n为偶(k!=1)计算a[i+1]与a[i]的距离,for(i+=2),这样我们就将它化成几点nim游戏问题,将a[i+1]与a[i]的距离左为每堆石子的个数

当n为奇数,就是a【1】自己当作一个堆,然后还是将a[i+1]与a[i]的距离左为每堆石子的个数,轮到谁没有石子取了,谁就输啦!当然注意特殊情况就是当n为奇数的时候,k如果为2,前面我们说当n为奇数是直接将第一个直接走到终点,但因为第二哥是k了,所以第一个a[i]不能走道终点,只能走道里终点最近的位置也就是只能走a[i]-1步,所以就是将a[i]-1当作一个堆

再说一下什么是nim游戏

通常的Nim游戏的定义是这样的:有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了,则判负(因为他此刻没有任何合法的移动)。

对于一个Nim游戏的局面(a1,a2,...,an),它是P-position当且仅当a1^a2^...^an=0,其中^表示异或(xor)运算。

为什么可以a1^a2^...^an=0 就判断先取的一定赢呢,首先是如果堆内的石子数量成对相等,这个应该都明白,就是2,2的情况或者4,4,9,9,这样,谁先取谁输,但如果是三组的呢,怎么办,用a1^a2^...^an=0,啊!!简洁的说就是将所有堆数全都分解成二进制堆,譬如9,5,12,谁先取谁输,为什么,就是9的二进制1001分成8和1,5的二进制0101分成4和1,12的二进制1100分成8和4,然后9,5,12就变成1,1,4,4,8,8了这不就是成对了么,就业是为什么a1^a2^...^an=0就可一判断谁先走谁输了

以上都是自己的一些理解,如有错误请指正哈!!!!(*^__^*) 嘻嘻……

代码如下

#include<iostream>
#include<cstdio>
using namespace std;
int a[1005],ans;
int n,k;
void move(){
    int i;
    if(n%2==0){
        for(i=1;i<=n;i+=2){
            ans^=(a[i+1]-a[i]-1);
        }
    }
    else{
        ans^=a[1];
        for(i=2;i<=n;i+=2){
            ans^=(a[i+1]-a[i]-1);
        }
    }

}
int main(){

    while(~scanf("%d%d",&n,&k)){
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        ans=0;
        if(k==1) {
            printf("Alice\n");
            continue;
        }
        if(k==2 && n%2==1){
            a[1]--;
            move();
        }
        else move();
//        cout<<ans<<endl;
        if(ans==0) printf("Bob\n");
        else printf("Alice\n");
    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

代码随想录

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

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

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

打赏作者

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

抵扣说明:

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

余额充值