題目
有 n
個不同價值的硬幣排成一條線。兩個參賽者輪流從左邊依次拿走 1 或 2 個硬幣,直到沒有硬幣為止。計算兩個人分別拿到的硬幣總價值,價值高的人獲勝。
請判定 第一個玩家 是輸還是贏?
給定數組 A = [1,2,2]
, 返回 true
.
給定數組 A = [1,2,4]
, 返回 false
.
解題
動態規划、博弈論
坑死,看了好久
定義dp[i]表示從i到end能取到的最大值
當我們在i處,有兩種選擇:
1.若取values[i],對方可以取values[i+1] 或者values[i+1] + values[i+2]
當對方取values[i+1] 后 ,我們只能從 i+2 到end內取,我們所取得最大值是dp[i+2], 注意:對方所選取的結果一定是使得我們以后選取的值最小
當對方取values[i+1] + values[i+2]后,我們只能從i+3到end內取,我們所取得最大值是dp[i+3]。
此時:dp[i] = values[i] + min(dp[i+2],dp[i+3]) , 注意:對方所選取的結果一定是使得我們以后選取的值最小
2.若取values[i] + values[i+1],對方可取values[i+2] 或者values[i+2] + values[i+3]
當對方取values[i+2]后,我們只能從i+3到end內取,我們取得最大值是dp[i+3]
當對方取values[i+2]+values[i+3]后,我們只能從i+4到end內去,我們取得最大值是dp[i+4]
此時:dp[i] = values[i] + values[i+1]+min(dp[i+3],dp[i+4])
這里的取最小值和上面一樣的意思,對方選取過之后的值一定是使得我們選取的值最小,對方不傻並且還很聰明
最后我們可以取上面兩個dp[i]的最大值,就是答案,這里意思是:對方留得差的方案中,我們選取的最大值。

public class Solution { /** * @param values: an array of integers * @return: a boolean which equals to true if the first player will win */ public boolean firstWillWin(int[] values) { // write your code here // dp 表示從i到end 的最大值 // int values[] ={1,2,4,3,4,8,5,6,12}; int len = values.length; // 長度小於2的時候第一個人一定獲勝 if(len <= 2) return true; int dp[] = new int[len+1]; dp[len] = 0; dp[len-1] = values[len-1]; dp[len-2] = values[len-1] + values[len - 2]; dp[len - 3] = values[len-3] + values[len - 2]; for(int i = len -4;i>=0;i--){ dp[i] = values[i] + Math.min(dp[i+2],dp[i+3]); dp[i] = Math.max(dp[i],values[i]+values[i+1]+ Math.min(dp[i+3],dp[i+4])); } int sum = 0; for(int a:values) sum +=a; return dp[0] > sum - dp[0]; } }
總耗時: 1114 ms