石子游戲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"
}
}