📜  Nim游戏的变化

📅  最后修改于: 2021-04-29 01:06:53             🧑  作者: Mango

先决条件:
斯普拉格·格兰西定理
肮脏的数字
Nim是著名的游戏,其中两个玩家轮流从不同的堆中移除物品。在每个回合中,玩家必须从单个非空堆中移除一个或多个物品。游戏的获胜者是从最后一个非空堆中删除最后一个项目的任何玩家。

现在,对于每个非空堆,任一玩家都可以从该堆中删除零个物品,并将其计为他们的移动;但是,任何一位玩家每堆只能进行一次此移动。
给定每堆物品的数量,确定谁将赢得比赛;玩家1或玩家2。如果玩家1开始游戏,并且双方都处于最佳状态。

例子:

Input : 3 [18, 47, 34]
Output : Player 2 wins
G = g(18)^g(47)^g(34) = (17)^(48)^(33) = 0
Grundy number(G), for this game is zero.
Player 2 wins. 

Input : 3 [32, 49, 58]
Output : Player 1 wins
G = g(31)^g(50)^g(57) = (17)^(48)^(33) = 20
Grundy number(G), for this game is non-zero.
Player 1 wins. 

方法:
每堆的脏数是根据石头的数量计算的。为了补偿零移动,我们将不得不修改标准nim游戏中使用的脏度值。
如果堆大小是奇数;脏号码是size + 1,
如果堆的大小是均匀的;脏号码是size-1。
我们对所有的脏钱数字值进行XOR运算,以检查游戏的最终Grundy数(G)是否为非零或不决定谁是游戏的获胜者。

解释:
状态的脏数是一次有效移动所不能达到最小正整数
因此,我们需要从下往上计算每个n的mex值,以便我们可以得出每个n的粗略数。其中n是堆的大小。

获胜状态:无论对手做什么,当前玩家从中赢得比赛的价值元组。 (如果G!= 0)
输球状态:无论对手做什么,当前玩家将从中输掉游戏的值的元组。 (如果G = 0)

For a given pile size n, we have two states:
(1) n with no zero moves available, 
grundy number will same as standard nim game.
(2) n with zero moves available, we can
reach above state and other states with 
zero moves remaining. 

For, n = 0, g(0) = 0, empty pile

For, n = 1, we can reach two states:
(1) n = 0 (zero move not used)
(2) n = 1 (zero move used)   
Therefore, g(1) = mex{0, 1} which implies
that g(1)=2.

For, n = 2, we can reach :
(1) n = 0 (zero move not used) state 
because this is a valid move.
(2) n = 1 (zero move not used) is a valid
 move, whose grundy nuber is 2.
Therefore, g(2) = mex{0,2} which implies 
that g(2)=1. 
note that n=1 (zero move used) is not a valid
move.

If we try to build a solution bottom-up
like this, it turns out that if n is even, 
the grundy number is n - 1 and when it is odd,
the grundy is n + 1.

下面是上述方法的实现:

C++
// CPP program for the variation
// in nim game
#include 
using namespace std;
 
// Function to return final
// grundy Number(G) of game
int solve(int p[], int n)
{
    int G = 0;
    for (int i = 0; i < n; i++) {
 
        // if pile size is odd
        if (p[i] & 1)
            
            // We XOR pile size+1
            G ^= (p[i] + 1);
 
        else // if pile size is even
 
            // We XOR pile size-1
            G ^= (p[i] - 1);
    }
    return G;
}
 
// driver program
int main()
{
    // Game with 3 piles
    int n = 3;
 
    // pile with different sizes
    int p[3] = { 32, 49, 58 };
 
    // Function to return result of game
    int res = solve(p, n);
 
    if (res == 0) // if G is zero
        cout << "Player 2 wins";
    else // if G is non zero
        cout << "Player 1 wins";
 
    return 0;
}


Java
// Java program for the variation
// in nim game
class GFG {
     
    // Function to return final
    // grundy Number(G) of game
    static int solve(int p[], int n)
    {
         
        int G = 0;
        for (int i = 0; i < n; i++) {
     
            // if pile size is odd
            if (p[i]%2!=0)
                 
                // We XOR pile size+1
                G ^= (p[i] + 1);
     
            else // if pile size is even
     
                // We XOR pile size-1
                G ^= (p[i] - 1);
        }
         
        return G;
    }
     
    //Driver code
    public static void main (String[] args)
    {
         
        // Game with 3 piles
        int n = 3;
     
        // pile with different sizes
        int p[] = { 32, 49, 58 };
     
        // Function to return result of game
        int res = solve(p, n);
     
        if (res == 0) // if G is zero
            System.out.print("Player 2 wins");
        else // if G is non zero
            System.out.print("Player 1 wins");
    }
}
 
// This code is contributed by Anant Agarwal.


Python3
# Python3 program for the
# variation in nim game
 
# Function to return final
# grundy Number(G) of game
def solve(p, n):
    G = 0
    for i in range(n):
 
        # if pile size is odd
        if (p[i] % 2 != 0):
             
            # We XOR pile size+1
            G ^= (p[i] + 1)
         
        # if pile size is even
        else:
 
            # We XOR pile size-1
            G ^= (p[i] - 1)
     
    return G
 
# Driver code
 
# Game with 3 piles
n = 3
 
# pile with different sizes
p = [32, 49, 58]
 
# Function to return result of game
res = solve(p, n)
 
if (res == 0): # if G is zero
    print("Player 2 wins")
     
else: # if G is non zero
    print("Player 1 wins")
     
# This code is contributed by Anant Agarwal.


C#
// C# program for the variation
// in nim game
using System;
class GFG {
 
    // Function to return final
    // grundy Number(G) of game
    static int solve(int[] p, int n)
    {
 
        int G = 0;
        for (int i = 0; i < n; i++) {
 
            // if pile size is odd
            if (p[i] % 2 != 0)
 
                // We XOR pile size+1
                G ^= (p[i] + 1);
 
            else // if pile size is even
 
                // We XOR pile size-1
                G ^= (p[i] - 1);
        }
 
        return G;
    }
 
    // Driver code
    public static void Main()
    {
 
        // Game with 3 piles
        int n = 3;
 
        // pile with different sizes
        int[] p = { 32, 49, 58 };
 
        // Function to return result of game
        int res = solve(p, n);
 
        if (res == 0) // if G is zero
            Console.WriteLine("Player 2 wins");
             
        else // if G is non zero
            Console.WriteLine("Player 1 wins");
    }
}
 
// This code is contributed by vt_m.


PHP


Javascript


输出:

Player 1 wins

时间复杂度: O(n)