我要开始辅导,所以我决定从算法课上解决一些旧问题。问题如下:
您正在销售报纸,并且每天您在一个十字路口开始您的路线并结束您的路线=您开始的地方的东北方向。城市街道在网格上,如下所示,您从(0,0)开始到(n,m)结束。
向北移动会将你从(x,y)带到(x,y +1)。向东移动会将您从(x,y)带到(x + 1,y)。在每个交叉路口(x,y),你停止出售报纸,并将收入r(x,y)。设OPT(n,m)表示从(0,0)到(n,m)的最佳步行的总收入。
我的伪代码使用自下而上的动态编程来解决这个问题如下:
Bottom-Up-Alg(n,m,s[][]) \\ n and m are coordinates and s holds the revenue at each coordinate (n,m)
opt = 0 \\ holds optimal revenue
opt += s[0][0] \\value at (0,0)
i = 0
j = 0
while (i <= n and j <= m)
if (s[i+1][j] > s[i][j+1])
opt += s[i+1][j] \\ Move east
i++
else
opt += s[i][j+1] \\ Move north
j++
return r
严格地说,该算法的运行时间为O(n + m)。但如果n和m成正比,那么运行时间可以说是O(n)或O(m)。
问题是我发现我的算法很贪婪,并且它不适用于所有情况。我在编写一般可以正常工作的伪代码时遇到了麻烦。
答案 0 :(得分:2)
您可以从右上角节点开始为每个节点编号,如果从该节点开始,可以获得最大收益,以及哪个先前节点为其提供最大值。 O(nm)的
您可以通过从右上角到左下角扫描对角线来完成此操作。
当这个编号到达左下方时,你有答案。 回顾一下。
22 19-17-15--9
|
27 26 17 16 14
|
35-32 22 22 20
补充:如果您想知道如何扫描对角线,可视化比编码更容易。
但是这里有一些C:
for (j = m-1; j >= -(n-1); j--){
for (ii = n-1; ii >= 0; ii--){
int jj = j + (n-1) - ii;
int rii = rjj = 0;
if (jj >= 0 && jj < m){
if (ii+1 < n && jj >= 0 && jj < m)
rii = r[ii+1][jj];
if (jj+1 < m && jj+1 >= 0)
rjj = r[ii][jj+1];
r[ii][jj] = s[ii][jj] + max( rii, rjj );
}
}
}
基本上,ii
和jj
是您正在处理的单元格的索引,如果其向右或向上的邻居位于矩形之外,则将其收入视为零。
答案 1 :(得分:2)
这是你的TA。我不禁注意到这个问题是在你的作业截止日期之前发布的。看到它现在已经过去了,您正在寻找的答案如下:
BOTTOM-UP-NEWSPAPER(n,m,r)
opt = array(n,m)
for i = 0 to n
for j = 0 to m
if i = 0 and j = 0 // In starting position
opt[i][j] = r(i,j)
else if i = 0 and j > 0 // On the south side of grid
opt[i][j] = r(i,j) + opt[i][j-1]
else if j = 0 and i > 0 // On the west side of grid
opt[i][j] = r(i,j) + opt[i-1][j]
else // Anywhere else
opt[i][j] = r(i,j) + max(opt[i-1][j], opt[i][j-1])
opt[n][m] holds the maximum revenue
答案 2 :(得分:0)
您的算法之所以有效,是因为它类似于Dijkstra算法,但能够在有向非循环图中找到最长路径,其中每个节点都有两个有向边。该算法以贪婪的方式找到关键路径。
运行时间应为O(mn)。这就像编辑距离的追溯程序一样。