问题
A和B两人轮流从n堆物品中取出一些物品,n堆物品的数量分别为[s1,s2,s3…sn](所有物品数量都是正整数)。
每人每次从一堆物品中至少取1个,多则不限,最后取光所有物品的人获胜。
给定n和[s1,s2,s3…sn],当我方先手,我方和对方都是高手(在能赢的情况下一定能赢),求我方是否能赢。
解法
(1) 当我方面临[0,7,0]局势(有1堆物品)时,我方必赢,因为我方可以一次把剩下一组的物品取光;
(2) 当我方面临[0,1,1,0,0]局势(有2堆物品且均剩1个)时,我方必输,因为我方必然留给对方只剩1堆物品的局势;
(3) 当我方面临[0,1,1,1,0]局势(有3堆物品且均剩1个)时,我方必赢,因为我方必然留给对方只剩2堆物品且均剩1个的局势;
(4) 当我方面临[3,4,5]局势时,暂时无法看出我方是否必赢;
本问题背后的数学模型叫NimSum,堆数组大小的二进制和,上面5个局势可以转化为:
s1=010=0002s2=710=1112s3=010=0002nim1=0⊕7⊕0=1 s1=010=0002s2=110=0012s3=110=0012s4=010=0002s5=010=0002nim2=0⊕1⊕1⊕0⊕0=0 s1=010=0002s2=110=0012s3=110=0012s4=110=0012s5=010=0002nim3=0⊕1⊕1⊕1⊕0=1 s1=310=0112s2=410=1002s3=510=1012nim4=3⊕4⊕5=2 可以看出,当我方面临⊕i=1nsi=s1⊕s2⊕⋯⊕sn=0局势时必赢,否则必输。
该算法时间复杂度为O(n)。
Nim Sum
源码
NimGame.h
NimGame.cpp
测试
NimGameTest.cpp