Комбинаторная теория игр | Набор 3 (Цифры Гранди / Числа и Мекс)
Мы представили комбинаторную теорию игр в выпуске 1 и обсудили игру Ним во втором выпуске.
Grundy Number — это число, которое определяет состояние игры. Мы можем определить любую беспристрастную игру (например, игру ним) в терминах числа Гранди.
Числа Гранди или Числа определяют, как может быть решена любая Беспристрастная Игра (не только Игра Ним), после того как мы вычислили Числа Гранди, связанные с этой игрой, используя Теорему Шпрага-Гранди.
Но прежде чем вычислять числа Гранди, нам нужно узнать о другом термине — Mex.
Что такое Мекс?
«Минимальный исключающий», также известный как «Mex», набора чисел — это наименьшее неотрицательное число, отсутствующее в наборе.

Как рассчитать числа Гранди?
Мы используем это определение: число/число Гранди равно 0 для игры, которая немедленно проиграна первым игроком, и равно Mex чисел всех возможных следующих позиций для любой другой игры.
Ниже приведены три примера игр и программ для расчета числа Гранди и Мекс для каждой из них. Вычисление чисел Гранди выполняется в основном с помощью рекурсивной функции, называемой функцией calculateGrundy(), которая использует функцию calculateMex() в качестве своей подпрограммы.
Пример 1
Игра начинается с кучи из n камней, и игрок, который ходит, может взять любое положительное количество камней. Рассчитайте числа Гранди для этой игры. Последний игрок, который ходит, выигрывает. Какой игрок выигрывает игру?
Поскольку, если у первого игрока 0 камней, он сразу же проиграет, поэтому Гранди (0) = 0.
Если у игрока 1 камень, то он может взять все камни и выиграть. Таким образом, следующая возможная позиция в игре (для другого игрока) — (0) камней.
Следовательно, Гранди (1) = Mex (0) = 1 [согласно определению Mex]
Точно так же, если у игрока 2 камня, то он может взять только 1 камень или может взять все камни и выиграть. Таким образом, следующая возможная позиция в игре (для другого игрока) — (1, 0) камней соответственно.
Следовательно, Гранди (2) = Mex (0, 1) = 2 [согласно определению Mex]
Точно так же, если у игрока «n» камней, то он может взять только 1 камень, или он может взять 2 камня…….. или он может взять все камни и выиграть. Таким образом, следующая возможная позиция в игре (для другого игрока) — (n-1, n-2,….1) камней соответственно.
Следовательно, Grundy(n) = Mex (0, 1, 2, ….n-1) = n [согласно определению Mex]
Мы суммируем первое значение Гранди от 0 до 10 в таблице ниже:

C++
/* A recursive C++ program to find Grundy Number for a game which is like a one-pile version of Nim. Game Description : The game starts with a pile of n stones, and the player to move may take any positive number of stones. The last player to move wins. Which player wins the game? */#include<bits/stdc++.h>using namespace std; // A Function to calculate Mex of all the values in// that set.int calculateMex(unordered_set<int> Set){ int Mex = 0; while (Set.find(Mex) != Set.end()) Mex++; return (Mex);} // A function to Compute Grundy Number of "n"// Only this function varies according to the gameint calculateGrundy(int n){ if (n == 0) return (0); unordered_set<int> Set; // A Hash Table for (int i=0; i<=n-1; i++) Set.insert(calculateGrundy(i)); return (calculateMex(Set));} // Driver program to test above functionsint main(){ int n = 10; printf("%d", calculateGrundy(n)); return (0);} |
Java
// A recursive Java program to find Grundy// Number for a game which is like a // one-pile version of Nim. Game // Description : The game starts// with a pile of n stones, and the// player to move may take any// positive number of stones. // The last player to move wins.// Which player wins the game? import java.util.*; class GFG{ // A Function to calculate Mex of all// the values in that set. public static int calculateMex(Set<Integer> Set) { int Mex = 0; while (Set.contains(Mex)) Mex++; return (Mex); } // A function to Compute Grundy Number// of "n". Only this function varies// according to the game public static int calculateGrundy(int n) { if (n == 0) return (0); // A Hash Table Set<Integer> Set = new HashSet<Integer>(); for(int i = 0; i <= n - 1; i++) Set.add(calculateGrundy(i)); return (calculateMex(Set)); } // Driver codepublic static void main(String[] args){ int n = 10; System.out.print(calculateGrundy(n));}} // This code is contributed by divyeshrabadiya07 |
Python3
""" A recursive Python3 program to find Grundy Number fora game which is like a one-pile version of Nim.Game Description : The game starts with a pile of n stones,and the player to move may take any positive number of stones. The last player to move wins. Which player wins the game? """ # A Function to calculate Mex of all the values in# that set.def calculateMex(Set): Mex = 0 while (Mex in Set): Mex += 1 return (Mex) # A function to Compute Grundy Number of "n"# Only this function varies according to the gamedef calculateGrundy( n): if (n == 0): return (0) Set = set() # A Hash Table for i in range(n): Set.add(calculateGrundy(i)); return (calculateMex(Set)) # Driver program to test above functionsn = 10;print(calculateGrundy(n)) # This code is contributed by ANKITKUMAR34 |
C#
// A recursive C# program to find Grundy// Number for a game which is like a // one-pile version of Nim. Game // Description : The game starts // with a pile of n stones, and // the player to move may take// any positive number of stones.// The last player to move wins.// Which player wins the game?using System;using System.Collections; using System.Collections.Generic; class GFG{ // A Function to calculate Mex of all// the values in that set. static int calculateMex(HashSet<int> Set) { int Mex = 0; while (Set.Contains(Mex)) Mex++; return (Mex); } // A function to Compute Grundy Number// of "n". Only this function varies// according to the game static int calculateGrundy(int n) { if (n == 0) return (0); // A Hash Table HashSet<int> Set = new HashSet<int>(); for(int i = 0; i <= n - 1; i++) Set.Add(calculateGrundy(i)); return (calculateMex(Set)); } // Driver codepublic static void Main(string []arg){ int n = 10; Console.Write(calculateGrundy(n)); }} // This code is contributed by rutvik_56 |
Javascript
<script>// A recursive javascript program to find Grundy// Number for a game which is like a // one-pile version of Nim. Game // Description : The game starts// with a pile of n stones, and the// player to move may take any// positive number of stones. // The last player to move wins.// Which player wins the game? // A Function to calculate Mex of all // the values in that set. function calculateMex( Set) { var Mex = 0; while (Set.has(Mex)) Mex++; return (Mex); } // A function to Compute Grundy Number // of "n". Only this function varies // according to the game function calculateGrundy(n) { if (n == 0) return (0); // A Hash Table var set = new Set(); for (i = 0; i <= n - 1; i++) set.add(calculateGrundy(i)); return (calculateMex(set)); } // Driver code var n = 10; document.write(calculateGrundy(n)); // This code contributed by aashish1995</script> |
Выход :
10
Приведенное выше решение можно оптимизировать с помощью динамического программирования, так как есть перекрывающиеся подзадачи. Реализацию на основе динамического программирования можно найти здесь.
Пример 2
Игра начинается с кучи из n камней, и игрок для хода может взять любое положительное количество камней, не превышающее 3. Последний игрок, который ходит, выигрывает. Какой игрок выигрывает игру? Эта игра представляет собой версию Нима с 1 стопкой.
Поскольку, если у первого игрока 0 камней, он сразу же проиграет, поэтому Гранди (0) = 0.
Если у игрока 1 камень, то он может взять все камни и выиграть. Таким образом, следующая возможная позиция в игре (для другого игрока) — (0) камней.
Следовательно, Гранди (1) = Mex (0) = 1 [согласно определению Mex]
Аналогично, если у игрока 2 камня, то он может взять только 1 камень или может взять 2 камня и выиграть. Таким образом, следующая возможная позиция в игре (для другого игрока) — (1, 0) камней соответственно.
Следовательно, Гранди (2) = Mex (0, 1) = 2 [согласно определению Mex]
Точно так же Гранди (3) = Mex (0, 1, 2) = 3 [согласно определению Mex]
А как же 4 камня?
Если у игрока 4 камня, то он может взять 1 камень или может взять 2 камня или 3 камня, но не может взять 4 камня (см. ограничения игры). Таким образом, следующая возможная позиция в игре (для другого игрока) — (3, 2, 1) камней соответственно.
Следовательно, Гранди(4) = Mex (1, 2, 3) = 0 [согласно определению Mex]
Таким образом, мы можем определить число Гранди любого n >= 4 рекурсивно как-
Гранди (n) = Mex[Гранди (n-1), Гранди (n-2), Гранди (n-3)]
Мы суммируем первое значение Гранди от 0 до 10 в таблице ниже:

C++
/* A recursive C++ program to find Grundy Number fora game which is one-pile version of Nim.Game Description : The game starts with a pile ofn stones, and the player to move may take anypositive number of stones up to 3 only.The last player to move wins. */#include<bits/stdc++.h>using namespace std; // A Function to calculate Mex of all the values in// that set. // A function to Compute Grundy Number of "n"// Only this function varies according to the gameint calculateGrundy(int n){ if (n == 0) return (0); if (n == 1) return (1); if (n == 2) return (2); if (n == 3) return (3); else return (n%(3+1));} // Driver program to test above functionsint main(){ int n = 10; printf("%d", calculateGrundy(n)); return (0);} |
Java
/* A recursive Java program to find Grundy Number for a game which is one-pile version of Nim.Game Description : The game starts witha pile of n stones, and the player tomove may take any positive number of stones up to 3 only.The last player to move wins. */import java.util.*; class GFG{ // A function to Compute Grundy // Number of "n" Only this function // varies according to the game static int calculateGrundy(int n) { if (n == 0) return 0; if (n == 1) return 1; if (n == 2) return 2; if (n == 3) return 3; else return (n%(3+1)); } // Driver code public static void main(String[] args) { int n = 10; System.out.printf("%d", calculateGrundy(n)); }} // This code is contributed by rahulnamdevrn27 |