问题描述
我正在努力获得最佳子结构来解决问题,即必须遵循的递归以及可以构建动态规划解决方案以优化时间复杂度的方法。
假设A和B有2种石头。有第一种石头 A 和第二种石头 B 类型。他们决定按照规则玩游戏,例如在每一回合中可以完成以下有效动作之一:
- 挑选一些第一种类型的石头
- 挑选一些第二种类型的石头
- 选择相同数量的两种类型的石头
他们必须在每一回合中至少挑选一块石头。谁走最后一步就赢得比赛。两者都发挥最佳。然而,在讲述比赛规则时,爱丽丝为了确保她赢得比赛而决定谁先走,有点作弊。
给定石头,确定爱丽丝是否采取第一步。
解决方法
您可以从获胜位置向后工作。
- 如果所有剩余的石头都是第二种类型中的第一种,或者每种类型的石头数量相等,则轮到玩家获胜 - 选择所有剩余的石头。
- 在任何其他位置,轮到该回合的玩家可以将第一种或第二种类型的石头数量减少一个或多个,或者可以将两种类型的石头数量减少一个或多个。如果所有结果头寸都赢了,这个头寸就是输了。如果至少有一个结果位置输了,玩家可以选择那个位置,所以这个位置赢了。
更正式地说,对于第一种类型为 A
块和第二种类型为 B
块的游戏,创建一个布尔值表 N[A+1,B+1]
,其中 true
表示获胜,false
表示失败。
然后像这样填充表格:
for (a = 0; a <= A; a++) {
for (b = 0; <= B; b++) {
if (a == 0 || b == 0 || a == b) {
// case 1,always winning
N[a,b] = true;
} else {
// case 2,winning if there is a losing position reachable
if (
there is an 1 <= i <= a,such that N[a-i,b] is false
OR there is an 1 <= i <= b,such that N[a,b-i] is false
OR there is an 1 <= i <= min(a,b),b-i] is false
) {
N[a,b] = true;
} else {
N[a,b] = false;
}
}
}
}
填完表格后,如果 N[A,B]
为真,Alice 应该开始,否则让 Bob 开始。
将此作为单独的答案发布,因为它与其他答案大不相同。我也会留下那个答案,因为这种技术对于类似的问题可能不是很有用。
通过手动运行每个类型 10 颗棋子的示例,我发现唯一的亏损头寸是 (1,2),(3,5),(4,7),(6,10)
。有一个整数序列搜索引擎,可以在给定序列开头的情况下搜索已知公式,称为 OEIS
所以有序列A072061,与这个序列相匹配。这教会了我们两件事:
- 这是一个已知问题,游戏通常被称为Wythoff's game
- 对于某个整数
(a(2*k),a(2*k+1))
和k
,所有亏损头寸都由公式a(n) = n*(1+(-1)^n)/4+floor((2*n+1-(-1)^n)*(1+sqrt(5))/8)
给出
因此要确定 Alice 是否应该开始,您可以使用给定的公式计算 (A,B)
是否为亏损头寸。