hdu2176(堆)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu2176(堆)相关的知识,希望对你有一定的参考价值。

这道题我题意都看了好一会,原谅我基础不扎实。

题意:从输入的数据中选择其中一个,分成两个数,将分成的第二个数与其他数相异或(“异或”运算符(^)相同为0,不同为1。0^0=0,1^0=1,1^1=0),若最终结果为1则输出Yes。将所有石堆的数目,进行异或操作,如果结果为0,则先取者负。如果不为0,则先取者胜,且将异或结果与各堆数目进行异或,结果比原来的数少,则可把原来数目取为异或结呆,使对方处于必败态

看了别人的解题思路:本题和前面写的那题思路是一样的。求出在第i堆取完石子后应该剩下多少个 与其它堆相异或等于0,这是留给对手的是必败态,所以只要求出其它堆的异或值就好了,因为两个相同的数异或以后才是0,。注意:大于10000的数据输入要用scanf啊,不然会超时。

尼姆博弈基本思想:

        两人从n堆物品中取任意个,先取完者胜。

        即将n堆物品的数量异或,得到的值如果为0,则先手败,反之先手胜。

        如果要求先手在胜的条件下,到奇异局势的方法数,则判断异或的值与每一堆原值异或后(结果应该表示该堆没有参加异或时的异或值)与原值比较大小,

如果小于,则方法数加一。且对应的方法后,该堆的数目应变为异或的值与每一堆原值异或的值。

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int main()
{
         int n,m[200000],k,i,s;//n是石子的堆数,数组m存储的是每堆石子的个数
         while(scanf("%d",&n)!=EOF)
         {
                   if(!n)
                   break;
                   s=0;
                   for(i=0;i<n;i++)
                   {
                        cin>>m[i];//根据NIMM博弈的推理策略,应该对每一堆的石子进行异或运算
                        s=s^m[i];//异或操作
                   }
                   if(!s)//s==0(必败态)先取者总是遇见非奇异局势(第一次就是非奇异局势)
                   {
                        printf("No\n");
                   }
                   else
                   {
                        printf("Yes\n");
                        for(i=0;i<n;i++)
                        {
                            k=s^m[i];
                            if(k<m[i])
                             printf("%d %d\n",m[i],k);
                        }
                   }
         }
         return 1;
}

以上是关于hdu2176(堆)的主要内容,如果未能解决你的问题,请参考以下文章

取(m堆)石子游戏 HDU2176(Nim博弈)

hdu2176(堆)

HDU 2176 取(m堆)石子游戏 (尼姆博奕)

ACM-尼姆博弈之取(m堆)石子游戏——hdu2176

HDU 2176 取(m堆)石子游戏 尼姆博弈

HDU 2176 取(m堆)石子游戏 && HDU1850 Being a Good Boy in Spring Festivaly