hdu1850 Being a Good Boy in Spring Festival 博弈 nim-sum定理

博客介绍了nim-sum定理在博弈论中的应用,特别是在hdu1850问题中的解决方案。当nim-game的nim-sum为0时,当前位置为必败点。通过计算所有堆的异或值,可以确定先手玩家如何采取策略以确保胜利。先手玩家可以取走一定数量的物品,使得剩余堆的异或值为0,从而达到必败状态。通过遍历每个堆并执行异或操作,可以找到获胜的方案数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

桌子上有M堆扑克牌;每堆牌的数量分别为Ni(i=1…M);两人轮流进行;每走一步可以任意选择一堆并取走其中的任意张牌;桌子上的扑克全部取光,则游戏结束;最后一次取牌的人为胜者。
现在我们不想研究到底先手为胜还是为负,我只想问大家:

——“先手的人如果想赢,第一步有几种选择呢?”

题解:先看nim-sum定理: 

 当nim游戏的某个位置:(x1,x2,x3),当且仅当其各部分的nim-sum = 0(即x1⊕x2⊕x3 = 0(也就是各部分的异或为0))

                   当前位置为必败点,这对于多个堆的情况同样适用。

有了这个东西就好办了,我们首先求出所有堆异或后的值,再用这个值去对每一个堆进行异或,令res = x1⊕sum(sum为所有堆的或异值)

如果res < x1的话,当前玩家就从x1中取走(x1-res)个,使x1乘下res这样必然导致所有的堆的异或值为0,也就是必败点,这就是一种方案

遍历每一个堆,进行上面的断判就可以得到总的方案数。

#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<vector>
#include<algorithm>
#define LL long long
#define maxn 10001
#define INF 2147483646
using namespace std;
int main()
{
    vector<int>v;
    int n,sum,count;
    while(cin>>n,n)
    {
        count=sum=0;
        v.clear();
        int x;
        for(int i=0;i<n;i++)
        {
            cin>>x;
            sum^=x; //异或
            v.push_back(x);
        }
        for(vector<int>::size_type i = 0 ;i!=v.size();i++)
        {
            x=v[i]^sum;
            if(x<v[i])
                count++;
        }
        cout<<count<<endl;
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值