我正在尝试解决基于图形的问题,这是声明:
我必须找到从标记位置到标记位置的最短路线(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)],
]
如果没有移除墙的选项,我可以使用Bfs
或Dijkstra
来找到最短的路线。这个问题在这里被问到:
here - 他们简单地使用完全穷举搜索,这对于大型矩阵来说非常糟糕,他们专注于基于语言的优化,这不是解决问题的好方法。
Someone asked it here - 接受的答案有以下方法:
从监狱门口开始进行广度优先搜索,找到 每个可通行空间距监狱门的距离。
从转义窗口开始另一个广度优先搜索,以查找 每个可通行空间距逃生舱的距离。
现在遍历墙壁,并考虑依次移除每个墙壁。
你知道每个可通行空间与监狱门的距离
和逃生舱,所以你可以立即计算出长度
穿过墙壁留下的空间的最短路线
你刚刚删除。
但我不清楚这是什么( 所以你可以立即计算出通过墙留下的空间的最短路线的长度 )意味着上面的第3步。
还有更好的方法吗?
是否可以通过动态编程解决,而不是使用图形?
答案 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)
和(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。