zoukankan      html  css  js  c++  java
  • HDU 1850 Being a Good Boy in Spring Festival(Nim博弈)

    打开题目网址http://acm.hdu.edu.cn/showproblem.php?pid=1850

     

    其实题目的意思很简单!就是一个Nim博弈!但是这道题里说的不是问谁获胜,而是问的获胜的方法有多少种!

    所以这样说来好像还挺有意思的。。。

    首先,我们必须知道,因为是起手,对于M堆扑克,最多有M种获胜的方法!为什么???还不清楚...)

     

    下面找了网有的一点解释。。。

    res = M1 ^ M2 ^ M3 …. ^ Mm取异或(^)得res,由异或的性质知:res ^ Mi = ( M1 ^ M2 …^M(i-1) ^ M(i+1) ^ … ^Mm ) 也就是说res对任意一个数取^可以的得到其他所有数的^值,

    例如:5 7 9;5^7^9=0101^0111^1001=1011=11;那么11^5=1011^0101=1110=0111^1001=14;

    那么要保证先手取后剩余局势处于必败点,那么只有保证在这5张牌的牌堆里取出一些牌后,可以使得x^1110=0即x=1110=14,另外这个牌堆数必须大于14才有可能达到这种状态;

    现在只有5张牌,显然不能,而对于牌堆9,有(res^9)=0010=2,9显然大于2,所以只需要拿走7张牌就可以让局势处于必败点!

    终于弄懂了,看起来代码简短,好像蕴含了好多内容其实想想也没有多少内容,其实就是在最基本的Nim博弈中增加了方案的规划

    想想看,在最后求出sum,也就是最后的异或结果之后,如果在和某一堆中的值异或的话
    其实就相当于是把这一堆从原来的所有堆中去掉了,这样的话就可以将所有的情况分开来看了
    这样sum^a[i]也就是没有加当前这一堆的sum,要想让对手成为必败态,就要在自己处理之后让sum变成零
    这样相异或的结果(sum^a[i])就应该是在当前堆中要去掉的,但是必须要保证的是当前的堆中有sum^a[i]
    个石子。。。

    */

    #include<iostream>
    using namespace std;
    const int n=105;
    int main()
    {
    	int i,temp,m,a[n],sum,count;
    	while(~scanf("%d",&m) && m!=0)
    	{
    		sum=0;
    		count=0;
    		for(i=0;i<m;i++)
    		{
    			scanf("%d",&a[i]);
    			sum^=a[i];//先把所有的值进行异或运算
    		}
    		if(sum==0)
    			cout<<0<<endl;//若nim-sum为0,则是必败点,否则是必胜点
    		else
    		{
    			for(i=0;i<m;i++)
    			{
    				temp=sum;
    				temp=temp^a[i];//这其实是nim-sum定理,sum与每个值抑或
    				
    				if(temp < a[i])//然后该堆就减少为异或后的值,这是由必胜点到必败点
    					count++;//但是注意该值肯定是小于之前的初始值
    			}
    			printf("%d
    ",count);
    		}
    		
    	}
    	return 0;
    }


     

  • 相关阅读:
    关于SUID、SGID、Sticky(转载)
    对Linux下TCP连接相关配置的优化记录(转载)
    ACL权限设置(转载)
    如何把一个命令加入到某个用户sudo的列表中(转载)
    菜鸟的逆袭 目标
    菜鸟的逆袭 自我介绍
    Weekly Work from表单练习
    CSS属性display的值及其描述
    CSS Position
    电源防反接保护电路
  • 原文地址:https://www.cnblogs.com/zswbky/p/5432053.html
Copyright © 2011-2022 走看看