我在解决 Misere Nim 游戏中的缺陷在哪里

Posted

技术标签:

【中文标题】我在解决 Misere Nim 游戏中的缺陷在哪里【英文标题】:Where is my flaw in solving the Misere Nim game 【发布时间】:2017-05-16 06:58:39 【问题描述】:

游戏是你有N一堆石头,每个玩家轮到他必须从一堆石头中移走至少1块石头,移走最后一块石头的玩家输了。

从基本案例开始,我在十几个案例中写出了获胜者

/*
    stones             | winner  | N | ones 
    ========================================
    1                | Second  | 1 |  1   
    i, i>1           | First   | 1 |  0
    1,1              | First   | 2 |  2
    1,i, i>1         | First   | 2 |  1
    i,j, i,j>1       | Second  | 2 |  0
    1,1,1            | Second  | 3 |  3
    1,1,i, i>1       | First   | 3 |  2
    1,i,j, i,j>1     | First   | 3 |  1
    i,j,k, i,j,k>1   | First   | 3 |  0
    1,1,1,1          | First   | 4 |  4
    1,1,1,i          | First   | 4 |  3
    1,1,i,j, i,j>1   | Second  | 4 |  2
    1,i,j,k, i,j,k>1 | First   | 4 |  1
    i,j,k,m, ...     | Second  | 4 |  0
*/

我想我从中推导出了一个公式

static string GetWinner(int[] piles)

    int n = piles.Length, m = piles.Count(stones => stones == 1);
    if(m == n) // one stone per pile
        return n % 2 == 0 ? "First" : "Second";
    // if here, m < n
    return n % 2 == 0 ? (m % 2 == 0 ? "Second" : "First") : "First";

但这导致测试用例 2,1,3 失败,这应该导致 "Second"

我尝试使用以下事实。

如果是2,一堆大于2 的任何数量的石头都会给出相同的结果。原因是如果它大于2 并且玩家没有在那个转牌圈将牌堆缩小到1 那么玩家基本上已经让他的对手转牌了。

但是,我可能有些不对劲..

【问题讨论】:

我不明白你为什么要测试N,据我所知游戏只与M有关,无论如何你可能想让你的问题更清楚 有多少玩家?如果游戏目标是宣布 1 个较松,这意味着应该有超过 1 个赢家。那么,当您需要找到较松的人时,为什么要找到赢家 【参考方案1】:

我认为您的以下陈述是错误的:

一堆大于 2 的石头如果是 2 会给出相同的结果

如果状态是 1,2,2,第一个玩家可以通过移除 1 个棋子获胜。如果状态为 1,2,3,则第一个玩家无法获胜。所以石头的数量是2还是3是有区别的。

因为如果它大于 2 并且玩家在该回合没有将牌堆缩小到 1,那么玩家基本上已经给了他的对手。

这是正确的,只是有时“希望”将回合让给其他玩家,即超越回合。

最佳策略与二进制表示中每堆中的项目数的异或有关。有关最佳解决方案和详细信息,请参阅https://en.wikipedia.org/wiki/Nim。

【讨论】:

【参考方案2】:

我无法深入理解答案背后的数学,但经过一些研究和优化,这是我为python3提出的解决方案:


from functools import reduce

def misereNim(s):
    if(max(s)==1):
        return "First" if (len(s) % 2 ==0) else "Second"
    else:
        xor = reduce((lambda x, y: x ^ y), s)
        return "Second" if xor == 0 else "First"

if __name__ == '__main__':

    s = [9, 8, 4, 4, 4, 7]

    result = misereNim(s)
    print(result)

【讨论】:

以上是关于我在解决 Misere Nim 游戏中的缺陷在哪里的主要内容,如果未能解决你的问题,请参考以下文章

琐事游戏得分不正确

LeetCode 292 Nim Game(Nim游戏)

Nim 游戏SG 函数游戏的和

ZOJ 3964 Yet Another Game of Stones Nim游戏变种

51nod 1069 Nim游戏 + BZOJ 1022: [SHOI2008]小约翰的游戏John(Nim游戏和Anti-Nim游戏)

博弈论Nim游戏:台阶集合拆分(AcWing)