題目連結:
題目意譯:
Alice 和 Bob 繼續在玩著他們的石頭堆遊戲。現在有若干顆石頭排成一列,其中每一顆石頭上頭都有寫著數字。而這些數字是以一個整數陣列 stoneValue 所給定。
Alice 和 Bob 輪流,而 Alice 是作為先手。在每一位玩家的回合中,該玩家可以從石頭列的開頭拿走 1 、 2 或 3 顆石頭。
每一位玩家的分數為他所拿走的石頭的數字之總和。每一位玩家一開始的分數皆為 0。
此遊戲的目標是在最終得到最高的分數,而贏家即為擁有最高分數的該位玩家。分數一樣即平手。此遊戲在沒有石頭拿的時候結束。
假設 Alice 和 Bob 按最佳策略遊玩。
如果 Alice 會贏,則回傳 "Alice";如果 Bob 會贏,則回傳 "Bob";如果平手,則回傳 "Tie"。
限制:
1 ≦ stoneValue.length ≦ 5 × 10 ^ 4
-1000 ≦ stoneValue[i] ≦ 1000
範例測資:
範例 1:
輸入: stoneValue = [1,2,3,7]
輸出: "Bob"
解釋: Alice 必輸。她最好的策略將會是拿走開頭 3 顆石頭並得到 6 分。Bob 將得到 7 分並贏得遊戲。
範例 2:
輸入: stoneValue = [1,2,3,-9]
輸出: "Alice"
解釋: Alice 在第一步中必須選擇前 3 顆石頭並把負數留給 Bob 拿才能贏。
如果 Alice 只選 1 顆石頭,則她的分數會變成 1 而 Bob 的分數將會變成 5。在下一步,Alice 將必須拿走數值為 -9 的石頭並輸掉遊戲。
如果 Alice 只選 2 顆石頭,則她的分數會變成 3 而 Bob 的分數將會變成 3。在下一步,Alice 將必須拿走數值為 -9 的石頭並輸掉遊戲。
注意到兩位玩家都會按最佳策略遊玩,因此 Alice 會選讓自己可以贏的情況。
範例 3:
輸入: stoneValue = [1,2,3,6]
輸出: "Tie"
解釋: Alice 贏不了。但她可以藉由拿走開頭 3 顆石頭來讓遊戲平手;否則她將會輸。
解題思維:
跟其他石頭遊戲類似(如
這題和這題),可以看到如果 Alice 拿 x 堆(x = 1 、 2 或 3)可以讓 Bob 贏不了甚至是輸掉,則 Alice 將會拿 x 堆。
因此可以看到本題也可以按照動態規劃的精神來解——即不知道要做哪些子問題,那就全做!
(令 n = stoneValue.length)
定義一陣列 D,其中 D[i] 代表著剩餘石頭為 stoneValue[i] ~ stoneValue[n - 1] 的時候「輪到」的玩家減去另外一位玩家的分數(不考慮「先前」的分數)最大為何。可以看到整個遊戲 Alice 在最佳情況下與 Bob 的分數差值會是 D[0]。而遞迴式為:
D[n - 1] = stoneValue[n - 1]
D[n - 2] = stoneValue[n - 2] + stoneValue[n - 1]
D[n - 3] = stoneValue[n - 3] + stoneValue[n - 2] + stoneValue[n - 3]
(以上三式為遞迴停止條件)
D[i] = max( stoneValue[i] - DP[i + 1],
stoneValue[i + 1] + stoneValue[i] - DP[i + 2]
stoneValue[i + 2] + stoneValue[i + 1] + stoneValue[i] - DP[i + 3]),其中 0 ≦ i < n - 3。
遞迴求解完 D[0] 之後只要判斷 D[0] 的正負號即可。如果 D[0] > 0,則 Alice 必贏;如果 D[0] < 0,則 Bob 必贏;如果 D[0] == 0,則平手。
此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。