树搜索算法:如何快速确定A是否具有可靠的策略

时间:2015-02-05 10:00:52

标签: algorithm tree

最初的问题是这样的:有99块石头,A和B正在玩一个游戏,每个人依次拿走一些石头,每转一个只能拿一根,两根,四根或六根石头,一个拿最后的石头胜利。如果A是第一个拿石头的人,那么在第一个回合中A应该采多少石头?

这似乎是一个非常复杂的树搜索测验,列出所有的分支,然后自下而上:带有最后一块石头的A叶子被标记为“胜利”;对于中间节点,无论策略B可能采取什么策略,如果A始终有办法到达标记为“win”的节点,则该节点也标记为“win”。

但这种方法非常耗时。是否有任何智能算法可以检查A是否有“保证赢”策略?

2 个答案:

答案 0 :(得分:6)

O(n)解决方案

如果我们从1,2,4或6颗宝石开始,A总会获胜,因为他会在第一步中将它们全部拿走。

如果我们从3开始,A无论他做什么都会失败,因为无论他是拿1还是2,B下2或1都会赢。

如果我们从5开始,A将首先取2,然后将B发送到上面的案例中,然后以3块石头开始。

如果我们从7开始,A将获得4,并B3发送到相同的案例{/ 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 = 3A没有确定的获胜策略。

答案 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)中解决问题。