给定一堆整数,玩家轮流从堆栈顶部移除1,2或3个数字。假设对手以最佳方式进行游戏而你先选择,我想出了以下递归:
int score(int n) {
if (n <= 0) return 0;
if (n <= 3) {
return sum(v[0..n-1]);
}
// maximize over picking 1, 2, or 3 + value after opponent picks optimally
return max(v[n-1] + min(score(n-2), score(n-3), score(n-4)),
v[n-1] + v[n-2] + min(score(n-3), score(n-4), score(n-5)),
v[n-1] + v[n-2] + v[n-3] + min(score(n-4), score(n-5), score(n-6)));
}
基本上,在每个级别比较选择1,2或3的结果,然后你的对手选择1,2或3。
我想知道如何将其转换为DP解决方案,因为它显然是指数级的。我正在努力解决这样一个事实:它有三个维度:你的选择数,对手的选择数和子问题大小,即似乎table[p][o][n]
的最佳解决方案需要要维护,p
是您选择的值的数量,o
是您的对手选择的数字,n
是子问题的大小。
我真的需要3个尺寸吗?我已经看到了类似的问题:http://www.geeksforgeeks.org/dynamic-programming-set-31-optimal-strategy-for-a-game/,但似乎无法适应它。
答案 0 :(得分:4)
以下问题可以转换为DP: -
score[i] = maximum{ sum[i] - score[i+1] , sum[i] - score[i+2] , sum[i] - score[i+3] }
此处score[i] means max score generated from game [i to n]
其中v[i] is top of stack
。 sum[i] is sum of all elements on the stack from i onwards
。可以使用 O(N)中的单独DP来评估sum[i]
。可以使用 O(N)
编辑: - 以下是JAVA中的DP解决方案: -
public class game {
static boolean play_game(int[] stack) {
if(stack.length<=3)
return true;
int[] score = new int[stack.length];
int n = stack.length;
score[n-1] = stack[n-1];
score[n-2] = score[n-1]+stack[n-2];
score[n-3] = score[n-2]+stack[n-3];
int sum = score[n-3];
for(int i=n-4;i>=0;i--) {
sum = stack[i]+sum;
int min = Math.min(Math.min(score[i+1],score[i+2]),score[i+3]);
score[i] = sum-min;
}
if(sum-score[0]<score[0])
return true;
return false;
}
public static void main(String args[]) {
int[] stack = {12,1,7,99,3};
System.out.printf("I win => "+play_game(stack));
}
修改: - 强>
要获得DP解决方案,您需要根据自身的较小实例可视化问题解决方案。例如,在这种情况下,由于两个玩家都在最佳地玩,在第一个玩家做出选择之后,第二个玩家还获得剩余堆栈的最佳分数,其中第一个的子问题。这里唯一的问题是如何在重现中表示它。要解决DP,您必须首先根据子问题定义递归关系,子问题以任何计算方式排在当前问题之前。现在我们知道无论第二名球员获胜,第一名球员如此有效地输掉第一名球员获得第二名球员total sum - score
。作为第二个玩家也能以最佳方式进行游戏,我们可以用递归方式表达解决方案。