石子游戏III
Alice 和 Bob 用几堆石子在做游戏。几堆石子排成一行,每堆石子都对应一个得分,由数组 stoneValue 给出。
Alice 和 Bob 轮流取石子,Alice 总是先开始。在每个玩家的回合中,该玩家可以拿走剩下石子中的的前 1、2 或 3 堆石子 。比赛一直持续到所有石头都被拿走。
每个玩家的最终得分为他所拿到的每堆石子的对应得分之和。每个玩家的初始分数都是 0 。比赛的目标是决出最高分,得分最高的选手将会赢得比赛,比赛也可能会出现平局。
假设 Alice 和 Bob 都采取 最优策略 。如果 Alice 赢了就返回 “Alice” ,Bob 赢了就返回 “Bob”,平局(分数相同)返回 “Tie” 。
示例1
输入:values = [1,2,3,7]
输出:“Bob”
解释:Alice 总是会输,她的最佳选择是拿走前三堆,得分变成 6 。但是 Bob
示例2
输入:values = [1,2,3,-9]
输出:“Alice”
解释:Alice 要想获胜就必须在第一个回合拿走前三堆石子,给 Bob 留下负分。
如果 Alice 只拿走第一堆,那么她的得分为 1,接下来 Bob 拿走第二、三堆,得分为 5 。之后 Alice 只能拿到分数 -9 的石子堆,输掉比赛。
如果 Alice 拿走前两堆,那么她的得分为 3,接下来 Bob 拿走第三堆,得分为 3 。之后 Alice 只能拿到分数 -9 的石子堆,同样会输掉比赛。
注意,他们都应该采取 最优策略 ,所以在这里 Alice 将选择能够使她获胜的
示例3
输入:values = [1,2,3,6]
输出:“Tie”
解释:Alice 无法赢得比赛。如果她决定选择前三堆,她可以以平局结束比赛,否则她就会输。
示例4
输入:values = [1,2,3,-1,-2,-3,7]
输出:“Alice”
提示
题解
有趣的一道零和博弈的题,每堆石子有个分数。
设表示堆的石子中先手最大得到的分数。
那么显然表示堆的石子最大的得分就是, 即
那么对于其他的有三种选择
- 取一堆石子,能够得到的分数为
其中表示的石子分数和,那么表示先手后能够再得到的分数
同理
- 取两堆石子,能够得到的分数为
- 取三堆石子,能够得到的分数为
那么对于得到分数方程可以化简一下
那么最终的转移方程为
最终的结果就是查看
与的关系,得到最终的结果。
代码
func max(a, b int) int {
if a> b{
return a
}
return b
}
func stoneGameIII(stoneValue []int) string {
var dp [51000]int
var sum int = 0
n := len(stoneValue)
for i := n-1;i>=0;i-- {
sum += stoneValue[i]
dp[i] = -0x7FFFFFFE
for j:=1;j<=3;j++{
dp[i] = max(dp[i], sum-dp[i+j])
}
}
if sum - dp[0] == dp[0] {
return "Tie"
} else if sum-dp[0] < dp[0] {
return "Alice"
} else {
return "Bob"
}
}