博弈——Nim博弈(hdu2176,1850,1851,1907,1849)

题目链接:

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

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

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

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

*如对必胜态,必败态不是很理解的请移步上篇博客http://blog.csdn.net/sm9sun/article/details/53229146


题目描述:先抛一个取石子问题:

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

假设:

          如果n为1时,那么对于我方来说是必胜态,我可以把全部石子拿走。

          如果n为2时,那么我需要做的是逼迫对方拿光其中一堆,当然对方也不傻,所以我需要把石子变成1:1这样对方就必须拿光一堆。

          所以,当我面对两堆不一样数量的石子时,我的操作是使其两堆石子数相等,之后无论对方怎么拿,我都再另一堆也拿相同的石子数,逐步逼近1:1

          可见,这种情况我方为必胜态,反之,如果有两堆相同的石子,我方为必败态。

          如果n>2呢?比如说3,那么先举几个例子看一下,如果含有0,比如说(0,2,2)那么就回到了(2,2)的状态。

         如果是(1,2,3)不难发现,我方处于必败态,因为我无法一步将其变为(0,n,n),而对方在我做任何操作

        (0,2,3)(1,1,3)(1,2,2)(1,0,3)(1,2,1)(1,2,0)后,都可以变成(0,n,n)

         在这样的博弈中,我们不会轻易的拿掉一个独立的1,因为独立的1是完全颠覆胜败的操作

         所以无论m有多少,我们都可以将其视为最终的m个0和1,这个1的奇偶性决定着此次博弈的胜败

         所以(1,2,3 )我们可以将(2,3)当作是(0,1),我们不妨认为胜者必然会通过一轮双方都取2的操作来使其局势变为(1,0,1)

         联系到0和1,我们就不难想到计算机中的二进制了,所以我们用到的就是计算机中的按位异或运算。

         当我们面对一个(a,b,c)时,我们想办法使c变成a^b即可达到必胜态,因为a^b^(a^b)=(a^a)^(b^b) =0^0

         m堆石子同理

         举个例子:题中的(3,6,9)即0011,0110,1001。

         0011^0110^1001的结果是1100,所以我们要看以上3个数字能否拿掉若干石子达到改变 1100这个值

         0011  ^ 1100=1111  即3-15  不满足

         0110  ^ 1100=1010  即6-10  不满足

         1001  ^ 1100=0101  即9-5    可行

         也就是说,我把9拿掉4后变成5,局势变为(3,6,5)0011,0110,0101

         0011^0110^0101其结果为0000   满足对方的必败态。


          

#include<stdio.h>
int main ()
{
  int a[200001],i,x,m;
  while(~scanf("%d",&m)&&m)
  {
  	x=0;
     for(i=1;i<=m;i++)
     {
       scanf("%d",&a[i]);
       x^=a[i];
     }
     if(!x)
     printf("No\n");
     else
     {
       printf("Yes\n");
       for(i=1;i<=m;i++)
       {
          if((x^a[i])<a[i])
          printf("%d %d\n",a[i],x^a[i]);
       }
     }
    }
    return 0;
}

 题目1850、1851、1907同上



题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1849


题目描述:一个1*n的棋盘,编号为0~n-1,有m个棋子(可重叠)在棋盘上,每次可以将一枚棋子左移直至编号0的位置

最后一位走棋者胜。


讲道理题目中棋子左移操作很仁义了(好评),因为这很容易能让我们联系到 当棋子到第0位置时即无法再移动。

所以这道题我们可以转化为:  有m堆石子(棋子),每堆石子有不同的个数(棋盘编号),你可以拿走若干个石子(左移),最后一位走棋者(直至一堆)为胜。


所以这也是完完全全没有任何加料的Nim博弈~

#include<stdio.h>
int main()
{
    int i,b,m;
    int nim;
    while(~scanf("%d",&m)&&m)
    {
        nim=0;
        for(i=0;i<m;i++)
        {
        scanf("%d",&b);
        nim^=b;
        }
 if(nim)
 printf("Rabbit Win!\n");
 else 
 printf("Grass Win!\n");

    }
return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值