博弈论 Nimm Games

如果我写的有不对的地方,请大牛指正!Thanks

什么是Nim?Nim是一种经典的博弈论模型,是组合游戏(Combinatorial Games)的一种,属于“Impartial Combinatorial Games”(以下简称ICG)。下面来一个经典的Nim游戏:

  有N堆石子,每堆有a[n]个,两个玩家进行博弈,轮流从N堆石子中的一堆取任意个数的石子,可以全部取走。当轮到某人取的时候发现面前已经没有石子了(囧),那这个人就输了。。。问是否有先手必胜策略?

 

       看完题之后有点摸不着头脑,仔细分析就会发现里面的玄机。

     如果只剩一堆石子,那么先手必胜(废话,全拿走就赢了);

  如果剩两堆石子,有两种情况:①两堆石子一样多,此时先手没有必胜策略,反而后手有必胜策略;

                ②两堆石子不一样多,可以取数量多的使两堆数量相等,则先手必胜。

  看完第二种情况是不是晕了?把两堆石子取相等之后,如果对手在某一堆里拿若干颗,你就可以在另一堆中拿同样多的颗数,这样必胜,不信自己试试;换言之,如果你面对两堆数量相同的石子,那么另一名玩家就可以用上面所说的必胜策略,所以你就会输的。

游戏玩完了,下面是定义:

   ICG问题的特征:

        1.两个人参与,交替走棋;

        2.可能的走法在一个有限的集合里选取;

        3.游戏局面无后效性,未来与过去无关;

        4.如果某选手无法走动,则判负;

    定义Previous-position,为上一次move的人有必胜策略的局面,即先手必败或后手必胜。

    定义Next-position,为本次move的人有必胜策略的局面,即先手必胜或后手必败。

 

    然后我们来结合问题分析一下:我们假设当前局面为(3,3),显然(3,3)是一个P-position。(3,3)的子局面(也就是通过合法移动可以导致的局面)有(0,3)(1,3)(2,3);(0,3)的子局面有(0,0)(0,1)(0,2),显然(0,0)是一个P-position,(0,3)是一个N-position。只要找到一个是P-position的子局面就能说明是N-position。(1,3)的后继中(1,1)是P-position(因为(1,1)的唯一子局面(0,1)是N-position),所以(1,3)也是N-position。同样可以证明(2,3)是N-position。所以(3,3)的所有子局面都是N-position,它就是P-position。通过一点简单的数学归纳,可以严格的证明“有两堆石子时的局面是P-position当且仅当这两堆石子的数目相等”。

    对于这类问题,有一个简单的算法,即求所有终止情况的异或和,如果异或和为0则为P-position,反之则为N-position。

 

    证明……这个证明写得比较蛋疼,结合自己理解,跟网上的比较相似,毕竟我又不是神马数学系的。

     需证明三个命题: 1、终止位置所有状态都为0为P-position;2、N-position局面一定可以移动到某个P-position;3、P-position的局面无法移动到某个P-position。

    命题一使用上面提到的证明。

    命题二:对于某个局面a[1..n],若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。不妨设a[1] xor a[2]xor...xor a[n]=k,则一定存在某个a[i],它的二进制表示在k的最高位上是1.这时a[i] xor k<a[i]一定成立。则我们可以将a[i]改变成a[i]'=a[i] xor k,此时a[1] xor a[2] xor ..xor a[i]xor...xor a[n]=a[1] xor a[2] xor...xor a[n] xor k=0。

    命题三:异或运算满足消去率。消去率即在一个无零因子的环中,对任意的a,b,c∈R,c≠0,如果ac=bc或ca=ba,则a=b。所以对于某个局面a[1..n],若a[1] xor a[2]xor ... xor a[n]=0,经过某种合法移动后满足a[1] xor a[2]xor ...xor a[i]' xor...xor a[n]=0,则可证明a[i]=a[i]',所以这不是合法移动。

    证明完毕。

    下面就用例题说明。

Matches Game
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 4928 Accepted: 2762

Description

Here is a simple game. In this game, there are several piles of matches and two players. The two player play in turn. In each turn, one can choose a pile and take away arbitrary number of matches from the pile (Of course the number of matches, which is taken away, cannot be zero and cannot be larger than the number of matches in the chosen pile). If after a player’s turn, there is no match left, the player is the winner. Suppose that the two players are all very clear. Your job is to tell whether the player who plays first can win the game or not.

Input

The input consists of several lines, and in each line there is a test case. At the beginning of a line, there is an integer M (1 <= M <=20), which is the number of piles. Then comes M positive integers, which are not larger than 10000000. These M integers represent the number of matches in each pile.

Output

For each test case, output "Yes" in a single line, if the player who play first will win, otherwise output "No".

Sample Input

2 45 45

3 3 6 9

Sample Output

No

Yes
中文翻译(软件翻译不了,还得人工- -):
   这是一个简单的游戏。在这个游戏里,有很多堆火柴很两个玩家。两个玩家轮流进行游戏。在每一回合中,玩家可以从一堆中取走任意数量的火柴(当然也可以全部取
走,但取走的数量不能为0或者大于堆中的火柴数)。如果一个玩家的回合过后,没有火柴剩余了,那么那个玩家就是胜利者。假设两个玩家都很聪明,你的任务就是告诉
我先取的玩家会不会赢。
program POJ_2234;

var i,a,n,ans:longint;

begin 

   while not eoln() do 

      begin   

          read(n); 

          read(ans);

          for i:=1 to n-1 do  

             begin 

                read(a);   

                ans:=ans xor a;  

            end;    

         if ans=0 then writeln('No')else writeln('Yes');

    end;

end.

你可能感兴趣的:(games)