首页 > 代码库 > LintCode刷题笔记-- CoinsInLine
LintCode刷题笔记-- CoinsInLine
动态规划
问题描述:
There are n coins with different value in a line. Two players take turns to take one or two coins from left side until there are no more coins left. The player who take the coins with the most value wins.
Could you please decide the first player will win or lose?
Given values array A = [1,2,2]
, return true
.
Given A = [1,2,4]
, return false
.
解题思路:
这道题如果没有博弈论的相关思想,是一道非常烧脑的题目,我按照一般动态规划的套路尝试了很久都没有成功的找出的递推方程,原因在于我一直在考虑如何可以让自己拿到最大的解,完全忽略了对方的行动。其实这道题目的真正的递推关系是存在于对方的行动。只有想明白这一点才能继续完成这一问题:
无论我如何取硬币,轮到对方行动的时候,对方都会选择一个对自己最优的解,换言之,他会给我留一下价值最小的解。
所以,当我方取到values[i]的时候,对方就会取到values[i+1],我方的结果是从i+2到end中选取一个最小的
对方也可能取到values[i+1]和values[i+2], 我方的结果是从i+3到end中选取最小的一个
当我方取到values[i]+values[i+1]的时候,对方就会依次取到i+3,i+4
所以这一问题应当是从后往前进行动态规划,解决前面的问题用到后面的最小解,最后用所有数列的总和减去dp[0]位置上的及结果进行大小比较:
参考代码:
1 public boolean firstWillWin(int[] values) { 2 // write your code her 3 int len = values.length; 4 if(len<=2) return true; 5 6 int[] dp = new int[len+1]; 7 dp[len] = 0; 8 dp[len - 1] = values[len-1]; 9 dp[len - 2] = values[len-1]+values[len-2];10 dp[len - 3] = values[len-2]+values[len-3];11 12 for(int i=len-4; i>=0; i--){13 dp[i] = values[i]+Math.min(dp[i+2], dp[i+3]);14 dp[i] = Math.max(dp[i], values[i]+values[i+1]+Math.min(dp[i+3],dp[i+4]));15 }16 17 int sum = 0;18 for(int i = 0; i<len; i++){19 sum += values[i];20 }21 return dp[0]>sum-dp[0];22 }
LintCode刷题笔记-- CoinsInLine