📌  相关文章
📜  预测游戏的获胜者|斯普拉格·格兰迪

📅  最后修改于: 2021-05-06 07:22:04             🧑  作者: Mango

给定一个4×4二进制矩阵。两个玩家A和B都在玩游戏,玩家可以在每个步骤中选择其中所有全为1的任何矩形并将全部1替换为0。无法选择任何矩形的玩家将输掉游戏。假设获胜者都以最佳状态玩游戏,而A则开始游戏,以此来预测获胜者。

例子:

方法:可以使用sprague-grundy定理解决问题。对斯普拉-格伦迪基础案例是格伦迪[0] = 0,这是在矩阵中的所有的位置被填充0,则B赢得它,因此0。在格伦迪,递归我们称之为格伦迪函数与所有可在状态可能的。

4×4矩阵可以表示为16位二进制数,其整数为65535(整数),其中每个位代表矩阵中的位置。以下是解决上述问题的步骤。

  • 将矩阵转换为int val。
  • 用val调用递归函数,该函数使用备注来生成脏值。
  • 在递归函数内部,可以通过生成所有可能的矩形(使用四个for循环)来访问所有脏状态。
  • 检查生成的矩形(如果它是矩阵的矩形)。然后,这是一个要被不满的人拜访的状态。
  • 要使用MEX获得Grundy的价值,请参阅此内容。
  • 如果递归返回0,则玩家B获胜,否则玩家A获胜。

下面是上述方法的实现

#include 
using namespace std;
  
// Gets the max value
int getMex(const unordered_set& s)
{
    int mex = 0;
    while (s.find(mex) != s.end())
        mex++;
    return mex;
}
  
// Find check if the rectangle is a part of the
// the original rectangle
int checkOne(int mat, int i, int j, int k, int l)
{
  
    // initially create the bitset
    // of original intValue
    bitset<16> m(mat);
  
    // Check if it is a part of the rectangle
    for (int x = i; x <= j; x++) {
        for (int y = k; y <= l; y++) {
            int pos = 15 - ((x * 4) + y);
  
            // If not set, then not part
            if (!m.test(pos)) {
                return -1;
            }
            m.reset(pos);
        }
    }
  
    // If part of rectangle
    // then convert to int again and return
    int res = m.to_ullong();
    return res;
}
  
// Recursive function to get the grundy value
int getGrundy(int pos, int grundy[])
{
  
    // If state has been visited
    if (grundy[pos] != -1)
        return grundy[pos];
  
    // For obtaining the MEX value
    unordered_set gSet;
  
    // Generate all the possible rectangles
    for (int i = 0; i <= 3; i++) {
        for (int j = i; j <= 3; j++) {
            for (int k = 0; k <= 3; k++) {
                for (int l = k; l <= 3; l++) {
  
                    // check if it is part of the original
                    // rectangle, if yes then get the int value
                    int res = checkOne(pos, i, j, k, l);
  
                    // If it is a part of original matrix
                    if (res != -1) {
  
                        // Store the grundy value
                        // Memorize
                        grundy[res] = getGrundy(res, grundy);
  
                        // Find MEX
                        gSet.insert(grundy[res]);
                    }
                }
            }
        }
    }
  
    // Return the MEX
    return getMex(gSet);
}
  
// Conver the matrix to INT
int toInt(int matrix[4][4])
{
    int h = 0;
  
    // Traverse in the matrix
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < 4; ++j)
            h = 2 * h + matrix[i][j];
    return h;
}
  
// Driver Code
int main()
{
    int mat[4][4] = { { 0, 1, 1, 0 },
                      { 0, 0, 0, 0 },
                      { 0, 0, 0, 0 },
                      { 0, 0, 0, 1 } };
  
    // Get the int value of the matrix
    int intValue = toInt(mat);
  
    int grundy[intValue + 1];
  
    // Initially with -1
    // used for memoization
    memset(grundy, -1, sizeof grundy);
  
    // Base case
    grundy[0] = 0;
  
    // If returned value is non-zero
    if (getGrundy(intValue, grundy))
        cout << "Player A wins";
    else
        cout << "Player B wins";
  
    return 0;
}
输出:
Player A wins

时间复杂度:

上)
辅助空间: O(N)