• hihocoder 1163 博弈游戏·Nim游戏


    1163 : 博弈游戏·Nim游戏

    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    今天我们要认识一对新朋友,Alice与Bob。 Alice与Bob总是在进行各种各样的比试,今天他们在玩一个取石子的游戏。 在这个游戏中,Alice和Bob放置了N堆不同的石子,编号1..N,第i堆中有A[i]个石子。 每一次行动,Alice和Bob可以选择从一堆石子中取出任意数量的石子。至少取1颗,至多取出这一堆剩下的所有石子。 Alice和Bob轮流行动,取走最后一个石子的人获得胜利。 假设每一轮游戏都是Alice先行动,请你判断在给定的情况下,如果双方都足够聪明,谁会获得胜利?

    输入

    第1行:1个整数N。表示石子堆数。1≤N≤100 第2行:N个整数,第i个整数表示第i堆石子的个数A[i],1≤A[i]≤10000

    输出

    第1行:1个字符串,若Alice能够获胜输出"Alice",否则输出"Bob"

    样例输入

    3
    3 2 1

    样例输出

    Bob

    思路:Nim游戏。

    Nim游戏是经典的公平组合游戏(ICG),对于ICG游戏我们有如下定义:
    1、两名选手;
    2、两名选手轮流行动,每一次行动可以在有限合法操作集合中选择一个;
    3、游戏的任何一种可能的局面(position),合法操作集合只取决于这个局面本身;局面的改变称为“移动”(move)。
    4、若轮到某位选手时,该选手的合法操作集合为空,则这名选手判负。

    对于第三条,我们有更进一步的定义Position,我们将Position分为两类:
    P-position:在当前的局面下,先手必败。
    N-position:在当前的局面下,先手必胜。

    他们有如下性质:
    1.合法操作集合为空的局面是P-position;
    2.可以移动到P-position的局面是N-position;
    3.所有移动都只能到N-position的局面是P-position。(即P-position的局面无法移动到N-position)

    在这个游戏中,我们已经知道A[] = {0,0,...,0}的局面是P局面,那么我们可以通过反向枚举来推导出所有的可能局面,总共的状态数量为A[1]*A[2]*...*A[N]。并且每一次的状态转移很多。
    虽然耗时巨大,但确实是一个可行方法。

    当然,我们这里会讲这个题目就说明肯定没那么复杂。没错,对于这个游戏有一个非常神奇的结论:

    对于一个局面,当且仅当A[1] xor A[2] xor ... xor A[N] = 0时,该局面为P局面。

    对于这个结论的证明如下:
    1. 全0状态为P局面,即A[i]=0,则A[1] xor A[2] xor ... xor A[N] = 0。

    2. 从任意一个A[1] xor A[2] xor ... xor A[N] = k != 0的状态可以移动到A[1] xor A[2] xor ... xor A[N] = 0的状态。
    由于xor计算的特殊性,我们知道一定有一个A[i]最高位与k最高位的1是相同的,那么必然有A[i] xor k < A[i]的,
    所以我们可以通过改变A[i]的值为A[i]'=A[i]^k,使得A[1] xor A[2] xor ... xor A[i]' xor ... xor A[N] = 0。


    3. 对于任意一个局面,若A[1] xor A[2] xor ... xor A[N] = 0,则不存在任何一个移动可以使得新的局面A[1] xor A[2] xor ... xor A[N] = 0。
    假设A[i] -> A[i]', 使得A[1] xor A[2] xor ... xor A[i]' xor ... xor A[N] = 0,由于xor满足消去率,所以A[i]'=A[i],这是一个不合法的移动。
    由于xor计算的特殊性,我们可以知道,一定是存在偶数个1时该位置的1才会被消除。若只改变一个A[i],无论如何都会使得1的数量发生变化,从而导致A[1] xor A[2] xor ... xor A[N] != 0。

    以上三条满足ICG游戏中N,P局面的转移性质,所以该结论的正确性也得到了证明。
     1 #include <stdio.h>
     2 
     3 int main(){
     4     int i, n, a = 0, t;
     5     scanf("%d", &n);
     6     for(i = 0; i < n; i++){
     7         scanf("%d", &t);
     8         a ^= t;
     9     }
    10     if(a == 0)
    11         printf("Bob");
    12     else
    13         printf("Alice");
    14     return 0;
    15 }
     
  • 相关阅读:
    开发进度1
    人月神话阅读笔记(1)
    仓库管理系统
    课程管理系统教程
    流与文件课后作业2加解密工作
    流与文件课后作业3
    今日学习时间记录
    Java字符串切片
    java_ 集合
    json基础教程|理解Json
  • 原文地址:https://www.cnblogs.com/qinduanyinghua/p/5717397.html
Copyright © 2020-2023  润新知