在矩阵中找到从单一来源到多个目的地的最佳路线的算法

时间:2018-09-04 11:30:46

标签: algorithm

问题陈述: 我们有一个m * n矩阵。起点是左上方的单元格。我们只能在矩阵中向下或向右移动。在矩阵中随机选择目的地。现在我们需要找到具有以下约束的最佳例程:

  1. 该路线上的每个节点只能有一个父节点,但最多可以有两个子节点。
  2. 最小化复制路径。 例如,如果我们的目的地如下所示:

first example

与其在左侧使用例程,不如在右侧使用例程。

  1. 宁愿先往右走再往下走,除非往下走的距离比往右短。

在下面的示例中,与其选择左手边的解决方案,不如选择右手边的解决方案,因为它通过从(2,0)向下移动1而不是右手向下移动到(2,1) 2(0,1)。

second example

其他示例如下所示,都是最佳例程。

7 more examples

我正在为此工作一段时间。我研究了一些算法,例如传递性约简和Dijkstra,但没有弄清楚。如果您想给我一些有关算法的提示,那将是很棒的。

谢谢!


编辑2:

我已经收到有关Dijkstra算法和使用动态编程的一些想法。我认为对于Dijkstra算法,如果您可以提供一些提示,可以将这个问题转换为一个很好的图形问题。我一直在研究算法,认为它的主要问题是不必访问单元格。在下面的示例中,如果我们删除目的地之一,则与左侧地图相比,整个例程将发生重大变化。

fourth example

对于动态编程,我对节点应如何连接到路径有一个想法。优先级应如下:

priority graph

但是问题在于它无法通过动态视图来考虑问题,这将输出错误的结果。

3 个答案:

答案 0 :(得分:1)

我认为您的示例都可以使用以下通用算法:从第一行和第一列的末尾开始,然后从第二行和第二列的末尾开始,等等,同时向左和向上遍历-从每个D遇到最接近的路线DS(当然,沿N-NW-W弧线的曼哈顿距离)。

示例7:

  1 2 3 4
1 S     D

2     D

3   D

4 D     D

  1 2 3 4
1 S-----D<
  |
2 |   D
  |
3 | D
  |
4 D     D
  ^

  1 2 3 4
1 S-----D
  |   |
2 |   D  <
  |
3 |-D
  |
4 D     D
    ^

  1 2 3 4
1 S-----D
  |   |
2 |   D
  |
3 |-D
  |
4 D-----D<
        ^

示例5:

  1 2 3 4
1 S

2       D

3     D

4 D     D

  1 2 3 4
1 S      <
  |
2 |     D
  |
3 |   D
  |
4 D     D
  ^

  1 2 3 4
1 S
  |
2 |-----D<
  |
3 |   D
  |
4 D     D
    ^

  1 2 3 4
1 S
  |
2 |-----D
  |   |
3 |   D  <
  |
4 D     D
      ^

  1 2 3 4
1 S
  |
2 |-----D
  |   |
3 |   D--
  |     |
4 D     D<
        ^

示例1:

  1 2 3 4
1 S

2     D

3   D   D

4     D

  1 2 3 4
1 S--
    |
2   --D  <
    |
3   D   D

4     D
    ^

  1 2 3 4
1 S--
    |
2   --D
    |
3   D---D<
      |
4     D
      ^

答案 1 :(得分:0)

这是一个递归问题。您应该尝试练习贪婪算法动态编程,并尝试进行一些分类以及一些混合编程问题,以更好地了解何时以及如何应用制作两者结合的算法。

使用分而治之方法来解决此问题。将自己放在移动光标的位置,然后考虑可以在每个节点上执行的一组有序逻辑操作,以解决问题。

几天后,我将添加我的算法来解决此问题。这是为了确保我不会意外地帮助某人在比赛中发热量。

您可以参考thisthis来对该技术有所了解。 我还发现了一个有趣的article与更好地了解递归有关。它可能不会提供很多信息,但是绝对是激励人的。

提示: 只有3个可能的地方可以找到未访问的目标节点,以便可以访问:

  1. 它在当前节点的正下方
  2. 它直接位于当前节点的右侧
  3. 它在当前节点右下角的某个地方

一种可能的算法是您递归:

  1. 检查您下方的节点,并通过递归函数调用(如果有)立即访问它。
  2. 检查当前水平级别中存在的最远节点,并在不进行递归调用的情况下为其绘制路径。

[编辑1:对不起,我忘了提到默认情况!!]

  1. 如果在光标的水平或垂直方向上没有节点, 向右移。 该算法看似简单,但可以解决问题。 它的复杂度也只有O(N)。

答案 2 :(得分:0)

感谢您的所有回答和评论。所有这些评论对我都很有价值,并激发了我的思维。

我现在想出一个利用现有Dijkstra算法和正确的节点遍历顺序的解决方案。现在,我们不再从左上角开始,而是将原始源作为目标。然后将所有方向都向后转,以便现在我们只能从一个节点向左或向上移动。解决方案如下所示:

  1. 构建加权图。所有左上边缘的权重为1,所有上边缘的权重为(m +1-col),因此上移例程的第一列(具有4 x 4矩阵)的权重均为5。重量图示例如下所示: enter image description here

  2. 将节点(0,0)添加到已建立的路由。

  3. 从左上角的节点(0,0)开始,检查其右侧的所有节点((0,0)至(0,n))。然后检查其底部的所有节点((1,0)至(m,0))。对于所有“源”节点(最初是目标节点),请使用Dijkstra算法找到返回“ 已建立路由”的最短路径,然后将Dijkstra算法中的所有节点添加到已建立路由中。

  4. 对所有节点(i,i)重复步骤3,直到最后一个节点((m,m)或(n,n))。

任何其他更有效的解决方案都将受到欢迎。另外,如果您发现此算法存在一个陷阱,那就太好了。该算法似乎有效,但是我感觉这不是最有效的方法。