奶牛零食 - 自下而上的动态规划

Posted

技术标签:

【中文标题】奶牛零食 - 自下而上的动态规划【英文标题】:Treats for the cows - bottom up dynamic programming 【发布时间】:2014-09-01 20:15:02 【问题描述】:

完整的问题陈述是here。假设我们有一个已知值的双端队列。每一轮,我们可以从一端或另一端取出一个值,而仍在队列中的值增加为value*turns。目标是找到最大可能的总值。

我的first approach 是使用简单的自上而下的 DP 和记忆。让i,j 表示值数组A[] 的“子数组”的开始、结束索引。

                A[i]*age if i == j
f(i,j,age) =
                max(f(i+1,j,age+1) + A[i]*age , f(i,j-1,age+1) + A[j]*age)

然而,事实证明这太慢了,因为有多余的堆栈调用。自底向上迭代应该更快。

m[i][j]A[] 的“子数组”的最大可达值,开始/结束索引为i,j。因为i <= j,我们只关心下三角部分。

这个矩阵可以使用m[i][j] = max(m[i-1][j] + A[i]*age, m[i][j-1] + A[j]*age)这一事实迭代构建,其中age在对角线上最大(A[]的大小并随着A.size()-(i-j)线性减小。

我在implementation 的尝试遇到了bus error。

所描述的算法是否正确?总线错误的原因是什么?

这是代码中唯一可能发生总线错误的部分:

for(T j = 0; j < num_of_treats; j++) 
    max_profit[j][j] = treats[j]*num_of_treats;
    for(T i = j+1; i < num_of_treats; i++)
        max_profit[i][j] = max( max_profit[i-1][j] + treats[i]*(num_of_treats-i+j),
                                max_profit[i][j-1] + treats[j]*(num_of_treats-i+j));

【问题讨论】:

看起来你应该可以很容易地通过使用一个体面的调试器自己解决它并逐步解决,然后再打扰 SO 社区! 请注意,以下语句:“我不明白为什么使用向量或动态分配会有帮助”和“我只使用它的一半”很有趣。 @πάνταῥεῖ 我当然试过了。如果没有外部帮助,我不会问我是否可以解决它...... 声明数组static 将其从堆栈中取出。 这不是最小的,也不是很远。 Minimal 是这样的:这是我的代码的一部分;它抛出这个错误;帮助?通常,不需要历史数据。 【参考方案1】:

for(T j = 0; j &lt; num_of_treats; j++)

在这个循环中,j 显然是数组max_profit 的有效索引。但你不只是使用j

【讨论】:

我使用的另一个索引i 有什么无效的? @mirgee:就我所见,i 没什么问题。请注意,问题似乎也存在于您的原始数学中。 您介意删除您的答案,以便我删除此问题吗?【参考方案2】:

总线错误是由于在调试过程中我应该注意到j=0i=1 时尝试通过负索引访问数组引起的。算法也是错误的。一、用于构造max_profit[][]数组的关系应该是

max_profit[i][j] = max( max_profit[i+1][j] + treats[i]*(num_of_treats-i+j),
                        max_profit[i][j-1] + treats[j]*(num_of_treats-i+j));

其次,数组必须对角填充,这样max_profit[i+1][j]max_profit[i][j-1] 就已经计算过了,主对角线除外。

第三,选择的数据结构效率极低。我只使用了分配给max_profit[][] 的一半空间。另外,在每次迭代中,我只需要最后计算的对角线。一个大小为num_of_treats 的数组就足够了。

Here 是使用这种改进算法的工作代码。我很喜欢。我什至是第一次使用位运算符。

【讨论】:

以上是关于奶牛零食 - 自下而上的动态规划的主要内容,如果未能解决你的问题,请参考以下文章

动态规划——奶牛接苹果

Python之动态规划算法

动态规划:0/1 背包 - 将组合检索为数组

动态规划 洛谷P1868 饥饿的奶牛

动态规划

动态规划