hdu1850-Being a Good Boy in Spring Festival (博弈论 Nim博弈)

Being a Good Boy in Spring Festival

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3972    Accepted Submission(s): 2345


Problem Description
一年在外 父母时刻牵挂
春节回家 你能做几天好孩子吗
寒假里尝试做做下面的事情吧

陪妈妈逛一次菜场
悄悄给爸爸买个小礼物
主动地 强烈地 要求洗一次碗
某一天早起 给爸妈用心地做回早餐

如果愿意 你还可以和爸妈说
咱们玩个小游戏吧 ACM课上学的呢~

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

Input
输入数据包含多个测试用例,每个测试用例占2行,首先一行包含一个整数M(1<M<=100),表示扑克牌的堆数,紧接着一行包含M个整数Ni(1<=Ni<=1000000,i=1…M),分别表示M堆扑克的数量。M为0则表示输入数据的结束。
 

Output
如果先手的人能赢,请输出他第一步可行的方案数,否则请输出0,每个实例的输出占一行。
 

Sample Input
  
  
3 5 7 9 0
 

Sample Output
1
 
             思路:如果所有堆的扑克牌数异或值等于0,那么先手为奇异局势(先手必输 在选手不犯错情况下)。由此某一堆扑克牌的异或值,等于剩余全部堆的异或值,那么此局是奇异局势,因为必胜局势必存在可以转换成奇异局势,那么某一堆的值 大于剩余堆扑克牌(也就是说这堆扑克牌可以取走某些数使其值等于剩余堆的异或数),那么这为一种必胜选择,遍历所有堆得出结果。
 
 
 
/***************************************************
*
*	acm: hdu-1850
*
*	title: Being a Good Boy in Spring Festival
*
*	time: 2014.5.4
*
***************************************************/

//此题考察博弈论,Nim博弈

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i;
    int j;
    int k;
    int M;   //M堆扑克牌

    while (~scanf("%d", &M) && M != 0)
    {
        int N[101] = {0};   
        int sum = 0;   //除当前堆,剩余堆得异或值
        int num = 0;   //必胜结果的选择数

        for (i=1; i<=M; i++)
        {
            scanf("%d", &N[i]);  //每一堆扑克牌的数量
        }

        for (i=1; i<=M; i++)
        {
            k = i;
            sum = 0;

            for (j=1; j < k; j++)  //当前堆之前的所有堆
            {
                sum ^= N[j];
            }

            for (j = i + 1; j <= M; j++)//当前堆之后的所有堆
            {
                sum ^= N[j];
            }

            if (N[k] > sum) //如果当前堆值大于 剩余堆的异或值 则结果胜利
            {
                num++;
            }
        }

        printf("%d\n", num);
    }

    return 0;
}
 

还有种思路,算是上面程序的优化把
/***************************************************
*
*	acm: hdu-1850
*
*	title: Being a Good Boy in Spring Festival
*
*	time: 2014.5.4
*
***************************************************/

/*
    理论:a+b=s,有 b=s+a  (a表示某分堆,b表示其余分堆的异或值,s为总异或值)
即总异或和s 对任意一个数a取异或 可以的得到其他所有数的异或值b。

	思路:if (b = s + a < a) 成立
 a可以减到b使其异或为0  则有必胜策略

e.g
s = 5 + 7 + 9 = 0101 + 0111 + 1001 = 1011B = 11D
b = s + a = 11 + 5 = 1011 + 0101 = 1110B = 14D
b = 7 + 9 = 0111 + 1001 = 1110B = 14D

because : a < b 
so:  从5取任何数都无法转为必败点

if (s != 0) 遍历剩余所以堆, 必存在能转为必败点的某堆

*/

#include<stdio.h>

#define MAXSIZE 100

int main()
{
    int M;
	int N[MAXSIZE];

    while (~scanf("%d", &M) && M != 0)
    {
        int i;
        int sum = 0;
		int num = 0;

        for (i = 0; i < M; i++)
        {
            scanf("%d", &N[i]);
            sum ^= N[i];
        }

		for (i = 0; i < M; i++)
		{
			if (N[i] > (N[i]^sum))
			{
				num++;
			}
		}

		printf("%d\n", num);

    }

    return 0;
}


 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值