任务定义:
我有一个自然数矩阵。任务是找到从矩阵的左上角到矩阵的右下角的路径并拨打最高分数。 导航规则:如果您位于[i] [j],您可以移动: a)到[i] [j-1],[i] [j + 1],[i + 1] [j]单元格并拨零点 b)到[i + 1] [j + 1]和拨号矩阵[i] [j]分
小例子:
假设您有score 50
和matrix
0 3 5 3 2
4 7 2 5 2
4 3 5 2 5
假设您在[1] [1]单元格中(矩阵[1] [1] = 7)。您可以导航至:
a) [1][0] cell with 50 score
b) [1][2] cell with 50 score
c) [2][1] cell with 50 score
d) [2][2] cell with 57 score
出了什么问题:
我以非常缓慢的方式解决这个问题...
我尝试在递归的帮助下实现。如果您只想找到最高分,这很容易。像
这样的东西public int loop(int i, int j) {
int left = loop(i, j-1);
int top = loop(i-1, j);
int diagonal = loop(i-1,j-1) + matrix[i-1][j-1];
return maximum(left, top, diagonal);
}
但是,我想找到一个得分最高的路径!这是非常耗时的时间。
为什么消耗时间/内存:
还有一个问题:我需要存储路径收集并将其作为参数传递给循环方法。但循环方法在每次迭代时都会分叉,我必须将路径集合复制到迭代次数。否则,每个循环分支将修改公共路径集合,最后我将拥有所有可能的路径。我的意思是如果在left
,top
和{ diagonal
最大的left
我们不得包含与top
和diagonal
相关联的路径。
问题:
如何以正确的方式解决?
修改 的
实际上没有必要找到完整的路径。它只需要找到你拨打分数的点(你可以在其中进行对角移动)
答案 0 :(得分:3)
您不需要动态编程,也不需要蛮力!
要了解原因,让我们分析一下规则:
j
(左右),所以没有理由对这个方向小心 - 你可以随时进入最佳水平位置。i
(向下),就无法回复(虽然你可以在没有获得积分的情况下增加i
)。 i
的每次增加都应该是最大点数。j
位置,然后采取一个对角线步骤;重复直到完成。i
步骤是从具有最高值的行中的非最后一个单元格移动。你不能从最后一个单元格移动,因为没有对角线移动可能 - 所以如果你的矩阵只有一列(或那个行),你永远不会获得积分。您不能丢失积分,因为值是自然数(但如果允许使用负数,您仍然可以跳过一行)。更详细地说,然后通过......找到最佳路径。
就是这样!
请注意,可能存在多个最大路径,您的问题规范并不能保证唯一的解决方案。
编辑:如果你不需要实际路径,只需要你得分的数字,那么算法就容易多了 - 删除或忽略最后一行和最后一列,然后是每个{{ 1}}(行)返回该行的最大值。
答案 1 :(得分:1)
编辑:
我误读了这个问题,只是向下移动到右边(即:j
只能改为j
或j+1
。)所以这个答案是错误的。
您可以使用动态编程来解决此问题。贪婪并不完全有效,因为你只能“向下和向右”旅行。
天真的动态编程解决方案在字面意义上基本上“向后工作”,从右下角开始,并在该单元格开始时计算最大分数。
从左右开始,从下到上,您可以简单地计算出从该分数中获得的最佳分数。您对m x n
矩阵执行此操作,然后从左上角开始并选择具有最大分数的方向。