我在解决 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 游戏中的缺陷在哪里的主要内容,如果未能解决你的问题,请参考以下文章
ZOJ 3964 Yet Another Game of Stones Nim游戏变种
51nod 1069 Nim游戏 + BZOJ 1022: [SHOI2008]小约翰的游戏John(Nim游戏和Anti-Nim游戏)