有 n 个硬币排成一条线, 第 i 枚硬币的价值为 values[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
int n = values.length;
int[][] dp = new int[n][n];
boolean[][] flag = new boolean[n][n];
int sum = 0;
for (int now : values)
sum += now;
return sum < 2 * MemorySearch(0, values.length - 1, dp, flag, values);
}
int MemorySearch(int left, int right, int[][] dp, boolean[][] flag, int[] values) {
if (flag[left][right])
return dp[left][right];
flag[left][right] = true;
if (left > right) {
dp[left][right] = 0;
} else if (left == right) {
dp[left][right] = values[left];
} else if (left + 1 == right) {
dp[left][right] = Math.max(values[left], values[right]);
} else {
int pick_left = Math.min(MemorySearch(left + 2, right, dp, flag, values),
MemorySearch(left + 1, right - 1, dp, flag, values)) + values[left];
int pick_right = Math.min(MemorySearch(left, right - 2, dp, flag, values),
MemorySearch(left + 1, right - 1, dp, flag, values)) + values[right];
dp[left][right] = Math.max(pick_left, pick_right);
}
return dp[left][right];
}
}