选择最佳矩阵

时间:2017-03-06 10:29:41

标签: algorithm matrix game-theory nim-game

我获得X大小为Ni*Mi的{​​{1}}矩阵1<=N<=4 and 1<=M<=4, for all 1 <= i <= X

游戏包括从给定X矩阵之一中选择任何矩形(子矩阵)并删除此子矩阵。

例如:我们有1个大小为4x4的矩阵。玩家1可以选择大小为4x4的子矩阵(在这种情况下为整个矩阵)并将其删除。或者他们可以选择2x21x12x3或任何有效子矩阵的子矩阵,并将其从4x4矩阵中删除,我们将剩余的矩阵留在游戏中。

无法移动的玩家输了。

哪位牌手赢了?

两位玩家都以最佳方式进行游戏。

2 个答案:

答案 0 :(得分:5)

这个问题通过Sprague Grundy theorem来解决,{{3}}表示当你对各个矩阵的nimbers进行xorbers时,移动的玩家只有在结果为0时才会失败(因为任何移动都会在一个胜利的位置,然后另一个玩家可以再次将胜利位置变为失败位置,依此类推,这就是类似游戏的游戏的本质。)

递归计算nimbers,矩阵的nimber是所有可达状态的nimber的mex(最小异或=集合中不存在的最小非负整数)。

所有0都是0,你没有有效的移动,因此它是一个损失(0)。

正好一个1是1,因为唯一可到达的位置是0而mex(0)= 1。

对于两个我们必须决定它们是否相邻,相邻= mex(0,1)= 2,不相邻= mex(1)= 0 ......等等。

示例:

1 0 0 0     1 1 0     1 1
0 0 1 1     0 0 0     1 1
0 0 1 0     0 0 1
0 0 0 0
   =          =        =
   2    xor   3   xor  1   =   0   => player to move loses.

快速实施可能如下所示:

  1. 预先计算16个(10个具有对称性)不同情况的nimbers并将它们存储在一个数组中。

  2. 分配结果= 0

  3. result = result xor nimbers [readRowCount()] [readColCount()]

  4. 重复3.直到读取所有矩阵尺寸

  5. 如果结果!= 0则第一个玩家赢得第二个玩家

  6. 示例2:nimber计算

    matrix:
    1 1
    1 1
    
    valid moves:
    0 1*  1 0*  1 1*  1 1*  0 0   1 1+  0 0+  1 0+  0 1+
    1 1   1 1   0 1   1 0   0 0   0 0   1 1   1 0   0 1
                             =
                             0 by definition
    
    The other matrices can be grouped into 2 groups * and + because of symmetries.
    
    Reachable positions from *:
    0 1   0 1   0 0
    0 1   1 0   0 1
     =     =     =
                 1 = mex(0), because the only reachable position has a nimber of 0
           0 = mex(1), because the only reachable position has a nimber of 1
     2 = mex(0,1), because the reachable positions have nimbers of 0 and 1
    
    ==> the nimber for * is mex(0, 1, 2) = 3.
    
    ==> we already know now that the nimber of + is 2.
    
    ==> the nimber of the given matrix is mex(0, 2, 3) = 1.
    

答案 1 :(得分:4)

(在maraca发表关于Sprague Grundy定理的答案之前,我试图确定游戏的最佳策略;我将在下面描述它,也许它也可以用来编写解决方案。 )

游戏的结果是每个矩形是否在奇数或偶数移动中被移除的结果。如果总移动次数是奇数,则玩家1获胜;如果是偶数,则玩家2获胜。

让我们来看看可能的矩形:

all 10 types of rectangles

对于所有&#34;正常&#34;矩形(2x2和1x1除外)首先删除其中一部分的玩家可以决定是否在奇数次移动中完全移除(例如,通过一次完全移除)或偶数次移动;以黄色显示的单元格显示第一个移动,使玩家处于控制之下。

对于&#34;瘦&#34;只有1个单元宽的矩形,立即采用奇数/偶数决策(通过移除整个矩形,或留下1个单元)。对于其他&#34;正常&#34;矩形,决定从1到3移动,取决于其他玩家的动作。

1x1矩形只能在一次移动中移除(即奇数移动)。可以在一次移动中移除2x2矩形,但是玩家不能仅通过移除部分移动来强制执行偶数移动;其他玩家总能决定奇数或偶数。

从图像中黄色指示的移动中可以看出,创建对称情况的移动(例如,将4x4方块划分为两个4x1矩形)会使创建此情境的人控制此矩形的结果。他可以,例如对此矩形强制执行偶数运动,如下所示:

force even in 4x4

对于整个游戏也是如此:如果玩家的移动导致对称情况(例如两个相同的L形和四个3x1矩形),他可以通过以下方式响应其他玩家的移动:镜像它们,然后当只有一个大于1x1的矩形时,他可以选择完全删除它或留下一个单元格(取决于剩下的单个单元格的数量是奇数还是偶数)并赢得游戏。

因此,策略归结为创造一个对称的情况,而不是让其他玩家有机会创造一个对称的情况。

注意:通过移除3x3,4x3或4x4矩形的中心并创建循环,可以创建更复杂的对称性。然后将它们旋转180度(即点镜像),而不是镜像其他玩家的移动。

基于这些想法的一些游戏结果:

  • 一个矩形:玩家1获胜。
  • 两个相同的矩形:玩家2获胜。
  • 1x1和一个薄矩形:玩家1胜。
  • 1x1和2x2矩形:玩家2获胜。
  • 1x1和更大的矩形:玩家1获胜。
  • 一个2x2和一个薄矩形:玩家1胜。
  • 一个2x2和一个更大的矩形:玩家1获胜。
  • 三个相同的矩形:玩家1获胜。
  • 1x1,2x2和任何其他矩形:玩家1获胜。
  • 偶数个相同的矩形:玩家2获胜。
  • 偶数个相同和任何其他矩形:玩家1获胜。
  • 奇数个相同的矩形:玩家1获胜。

下面是Sprague-Grundy定理的一个实现,正如maraca的回答中所解释的那样。它使用预先计算的nimbers列表,用于最大4x4的矩形。

&#13;
&#13;
function outcome(rectangles) {
    var n = 0, nimbers = [[1,2,3,4],[2,1,5,8],[3,5,4,7],[4,8,7,3]];
    for (var i = 0; i < rectangles.length; i++) {
        n ^= nimbers[rectangles[i][0] - 1][rectangles[i][1] - 1];
    }
    return n > 0 ? 1 : 2;
}
document.write("Player " + outcome([[3,3],[3,4],[4,4]]) + " wins.<br>");
document.write("Player " + outcome([[1,1],[2,2],[3,3],[4,4]]) + " wins.");
&#13;
&#13;
&#13;

任何4x4矩阵的nimber都可以使用下面的算法计算。 4×4矩阵由16位模式表示,例如, 65535是一个填充了1的矩阵。预先计算表示为位模式的所有矩形(可能的移动)的列表。

&#13;
&#13;
function nimber(matrix) {
    var rect = [   1,    2,    3,    4,    6,    7,    8,   12,   14,   15,
                  16,   17,   32,   34,   48,   51,   64,   68,   96,  102,
                 112,  119,  128,  136,  192,  204,  224,  238,  240,  255,
                 256,  272,  273,  512,  544,  546,  768,  816,  819, 1024,
                1088, 1092, 1536, 1632, 1638, 1792, 1904, 1911, 2048, 2176,
                2184, 3072, 3264, 3276, 3584, 3808, 3822, 3840, 4080, 4095,
                4096, 4352, 4368, 4369, 8192, 8704, 8736, 8738,12288,13056,
               13104,13107,16384,17408,17472,17476,24576,26112,26208,26214,
               28672,30464,30576,30583,32768,34816,34944,34952,49152,52224,
               52416,52428,57344,60928,61152,61166,61440,65280,65520,65535];
    var memo = [0];                                    // nimber of empty matrix is 0
    return nim(matrix);

    function nim(current) {
        if (memo.hasOwnProperty(current)) return memo[current]; // use memoized value
        var exclude = [];                       // set of nimbers of reachable states
        for (var i = 0; i < rect.length; i++) {
            if ((current & rect[i]) == rect[i]) {   // this rectangle is a valid move
                var next = current & ~rect[i];                    // remove rectangle
                exclude[nim(next)] = true;           // recurse and add nimber to set
            }
        }
        return (memo[current] = mex(exclude));                 // memoize this nimber
    }
    function mex(n) {                              // minimum excludant of nimber set
        var m = 0;
        while (n[m]) ++m;
        return m;
    }
}

document.write(nimber(65535));   // 0b1111111111111111 represents a filled 4x4 matrix
&#13;
&#13;
&#13;

表示4x4矩阵中所有大小,位置和方向的矩形的16位模式列表可以这样生成:

&#13;
&#13;
function rectangles(width, height) {
    var rect = [], line = (1 << width) - 1;
    for (var y = 0; y < height; y++) {
        for (var x = 0; x < width; x++) {
            for (var h = 1; h <= height - y; h++) {
                for (var w = 1; w <= width - x; w++) {
                    var bits = ((line >> (width - w)) << (width - x - w)) << (y * width)
                    for (var row = 1; row < h; row++) {
                        bits |= (bits << width);
                    }
                    rect.push(bits);
                }
            }
        }
    }
    return rect;
}
document.write(rectangles(4,4));
&#13;
&#13;
&#13;