扭曲网格中的最短路径

时间:2017-04-28 09:56:49

标签: algorithm dynamic-programming graph-theory dijkstra breadth-first-search

我正在尝试解决基于图形的问题,这是声明: 我必须找到从标记位置到标记位置的最短路线(S)[注意我标记为S和E只是为了便于理解]。这是问题的问题,我只能通过标记为0的单元格,标记为1的单元格代表无法通行的墙壁。我还可以选择remove only one wall,如果它让我退出更短的路线。 移动只能在基本方向上进行;不允许对角线移动。

示例2d网格:

[
    [0(S) 1  1  1  1   ], 
    [0    0  1  1  1   ],
    [1    0  1  0  1   ],
    [1    1  0  0  0(E)],
]

如果没有移除墙的选项,我可以使用BfsDijkstra来找到最短的路线。这个问题在这里被问到: here - 他们简单地使用完全穷举搜索,这对于大型矩阵来说非常糟糕,他们专注于基于语言的优化,这不是解决问题的好方法。

Someone asked it here - 接受的答案有以下方法:

  • 从监狱门口开始进行广度优先搜索,找到 每个可通行空间距监狱门的距离。

  • 从转义窗口开始另一个广度优先搜索,以查找 每个可通行空间距逃生舱的距离。

  • 现在遍历墙壁,并考虑依次移除每个墙壁。 你知道每个可通行空间与监狱门的距离 和逃生舱,所以你可以立即计算出长度 穿过墙壁留下的空间的最短路线
    你刚刚删除。

但我不清楚这是什么( 所以你可以立即计算出通过墙留下的空间的最短路线的长度 )意味着上面的第3步。

还有更好的方法吗?

是否可以通过动态编程解决,而不是使用图形?

1 个答案:

答案 0 :(得分:1)

我只想稍微增加图表如下:构建一个新图G',它是初始图G的两倍。 G'的每个节点表示状态(v, rem),其中v是G的节点,rem \in {0, 1}表示您是否已删除节点。还要添加一个额外的节点E_new

G'中的邻接如下:

  • 所有(v, 0) s(resp。(v, 1) s)都在G之间相互链接(如果它们都有值0)。
  • 如果v1的值为0且其中一个neihbors v2的值为1,则在(v1, 0)(v2, 1)之间添加边
  • (E, 0)(E, 1)都以{0}的价格与E_new相关联。(如果您不使用费用,则最后只删除1到长度)。

您现在的目标是从(s, 0)转到E_new,Dijkstra(如果所有步骤费用相同,则为BFS)应该最多能够及时工作O(n)其中n是你的节点数(不是方形的一边)。 A *会更快但实现起来有点棘手。如果您希望解决方案不需要移除墙壁(在等长处),则必须注意您执行BFS的顺序(首先是rem = 0的节点)。

这与Shortest path in matrix with obstacles with cheat paths的(实际上是一个实例)非常相似。

修改 你上面提到的答案具有相同的复杂性,需要2个BFS而不是1个,但是在图形上小两倍,所以可能相似,加上另一个循环,所以我不知道哪一个更快。

  

(所以你可以立即计算出最短路线的长度   穿过墙壁留下的空间)

在步骤1和步骤2中,您一方面计算了源和每个墙之间的排序路径,另一方面计算了出口和所有墙之间的排序路径,而没有穿过任何墙。通过为给定的墙节点添加这两个值,您只能获得从s到e的路径长度。通过遍历所有墙壁(或者如果你巧妙地完成它们的至少一部分),你得到最短的这样的路径,你可以比较最短的(s,e)路径而不穿过任何墙壁,只保留最好的一个。

编辑2

这是我的方法的一个小例子: 假设你的网格是这样的:

[[0, 0, 1],
 [0, 1, 0]]

其中的节点可以用它们的坐标(1,1),(1,2)等表示。 存在的唯一边缘是(1,1)至(1,2)和(1,1)至(2,1),以及(3,1)和(2,2)至(3,2)。为每个节点添加第三维rem,可以取值0或1.对于rem的每个值,if(i1,j1) - >(i2,j2)在图中,你现在有(i1,j1, rem) - >(i2,j2,rem)。对于不在图中的所有边(i1,j1) - >(i2,j2)(因为墙),你现在有(i1,j1,0) - >(i2,j2,1)。另外,最后,(2,3,0) - > E_new和(2,3,1) - > E_new。您可以在此新图表中运行BFS。