zoukankan      html  css  js  c++  java
  • [hihoCoder] 博弈游戏·Nim游戏

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

    描述

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

    提示:Nim?!

    输入

    第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。

    在这个游戏中,我们已经知道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[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。由于xor计算的特殊性,我们可以知道,一定是存在偶数个1时该位置的1才会被消除。若只改变一个A[i],无论如何都会使得1的数量发生变化,从而导致A[1] xor A[2] xor ... xor A[N] != 0。
    以上三条满足ICG游戏中N,P局面的转移性质,所以该结论的正确性也得到了证明。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int n, p, a;
     5 
     6 int main() {
     7     while (cin >> n) {
     8         for (int i = 0; i < n; ++i) {
     9             cin >> a;
    10             if (i == 0) p = a;
    11             else p ^= a;
    12         }
    13         if (p == 0) cout << "Bob" << endl;
    14         else cout << "Alice" << endl;
    15     }
    16     return 0;
    17 }
  • 相关阅读:
    python基本数据类型(—)
    linux基本命令
    1、认识Mysql
    Flask-SQLAlchemy详解
    sqlalchemy基本增删改查
    pymongo方法详解
    uWSGI+Nginx部署
    uwsgi
    nginx负载均衡配置
    redis-sentinel主从复制高可用(哨兵)
  • 原文地址:https://www.cnblogs.com/easonliu/p/4472541.html
Copyright © 2011-2022 走看看