最初的问题是这样的:有99块石头,A和B正在玩一个游戏,每个人依次拿走一些石头,每转一个只能拿一根,两根,四根或六根石头,一个拿最后的石头胜利。如果A是第一个拿石头的人,那么在第一个回合中A应该采多少石头?
这似乎是一个非常复杂的树搜索测验,列出所有的分支,然后自下而上:带有最后一块石头的A叶子被标记为“胜利”;对于中间节点,无论策略B可能采取什么策略,如果A始终有办法到达标记为“win”的节点,则该节点也标记为“win”。
但这种方法非常耗时。是否有任何智能算法可以检查A是否有“保证赢”策略?
答案 0 :(得分:6)
O(n)解决方案
如果我们从1,2,4或6颗宝石开始,A
总会获胜,因为他会在第一步中将它们全部拿走。
如果我们从3开始,A
无论他做什么都会失败,因为无论他是拿1还是2,B
下2或1都会赢。
如果我们从5开始,A
将首先取2,然后将B
发送到上面的案例中,然后以3块石头开始。
如果我们从7开始,A
将获得4
,并B
将3
发送到相同的案例{/ 1}}。
如果我们从8开始,无论他做什么,A
都将失败:无论他做什么,他都会将B
发送到获胜位置。
如果我们从9开始,A
可以取1并将B
发送到8的情况,导致他失败。
如果我们从10开始,A
可以取2并将B
再次发送到8的情况,导致他输了。
到目前为止,如何逐步构建O(n)
解决方案应该非常明显:让win[i] = true if i stones are winnable for the first person to move
我们有:
win[1] = win[2] = win[4] = win[5] = win[6] = true, win[3] = false
win[x > 6] = not (win[x - 6] and win[x - 4] and win[x - 2] and win[x - 1])
例如:
win[7] = not (win[1] and win[3] and win[5] and win[6])
= not (true and false and true and true)
= not false
= true
计算这个数字,直到你感兴趣的数字为止。没有树木参与。
O(1)解决方案
通过仔细研究上述解决方案,我们可以推导出一个简单的恒定时间解决方案:请注意A
只有在B
发送到获胜位置时才会失败,无论他做什么,所以如果k - 6, k - 4, k - 2, k - 1
都是胜利的职位。
如果您为一些值计算win
,则模式变得明显:
win[k] = false if k = 3, 8, 11, 16, 19, 24, 27, 32...
=> win[k] = false iff k mod 8 == 3 or k mod 8 == 0
对于99,99 mod 8 = 3
,A
没有确定的获胜策略。
答案 1 :(得分:1)
好的,我们可以看到:
每转一圈,可以采取的石头数量小于7 ,因此结果应与模数7 相关。
因此,对于n< 1000,我已经打印出第一个人获胜的石头序列,模数7,这是一个真正重复的循环。
1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5 0 1 3 4 5 6 1 2 4 5 6 0 2 3 5 6 0 1 3 4 6 0 1 2 4 5 0 1 2 3 5 6 1 2 3 4 6 0 2 3 4 5
这个循环的长度是56,所以通过查找前56个数字的结果可以在O(1)中解决问题。