我遇到了一个应该使用动态编程的问题,但是我真的很困惑。我真的很想确切地了解该如何处理。
问题如下:给您一个大小为N的数组,每个条目代表一个具有给定值的城市。在每个回合中,您必须选择在何处建墙。然后,“敌人”选择从哪一侧(东侧或西侧)发动进攻,摧毁所有城市,直到隔离墙。您只能从仍然存在的城市中收集价值。敌人最佳地摧毁了城市,这意味着它总是使您在游戏结束时能获得的价值最小化(而不是贪婪地使每一轮都变小)。
简单示例:
数组:8,6,2,4,2
第一轮-最佳选择是在价值6的城市和价值2的城市之间建造。敌人的进攻来自西方,导致价值8的城市被收集。
第二轮-最好的选择是在价值2的城市和价值4的城市之间建造。敌人从东方发动的攻击会导致价值2的城市被收集。
此游戏的总价值为10。
我正在寻找一个递归公式,以求得每个游戏我可以得到的最大价值。我想使用此递归公式来创建动态编程算法。任何帮助将不胜感激。
答案 0 :(得分:0)
这里的想法似乎可以与您提供的示例配合使用。尽管没有更多测试可确认,但它可能并不完全可靠,但可以帮助您考虑一下。请查看代码中的注释。 (前两个功能是帮助有效地计算子数组的和。)
function getPrefixSums(A){
var ps = new Array(A.length + 1).fill(0)
for (let i=0; i<A.length; i++)
ps[i+1] = A[i] + ps[i]
return ps
}
function getSum(ps, l, r){
return ps[r+1] - ps[l]
}
function f(A, ps, l, r){
// No moves available
if (l == r)
return 0
// One choice to place wall
if (l + 1 == r)
return Math.min(A[l], A[r])
// For each of our available choices,
// the enemey will choose the side
// that guaratees we get the least.
// Choose the BEST of these.
let goodForUs = -Infinity
for (let i=l+1; i<=r; i++){
let west = getSum(ps, i, r) + f(A, ps, i, r)
let east = getSum(ps, l, i-1) + f(A, ps, l, i-1)
if (east > west){
// Enemy chose west
if (west > goodForUs)
goodForUs = west
// Enemy chose east
} else if (east > goodForUs){
goodForUs = east
}
}
return goodForUs
}
var A = [8, 6, 2, 4, 2]
var ps = getPrefixSums(A)
console.log(f(A, ps, 0, A.length-1))