如何计算网格中两点之间的最短路径

时间:2010-02-22 14:33:58

标签: algorithm shortest-path

我知道有很多算法可用于计算图形或网格中两点之间的最短路径,如广度优先,全对(Floyd's),Dijkstra's。

然而,正如我所注意到的,所有这些算法都会计算该图或网格中的所有路径,而不仅仅是我们感兴趣的两点之间的路径。

我的问题是: 如果我有一个网格,即一个二维数组,我有兴趣计算两点之间的最短路径,比如P1和P2,如果我可以在网格上移动的方式有限制(例如只对角线,或只对角和向上等), 什么算法可以计算出来?

请注意,如果您有答案,我希望您发布算法的名称而不是算法本身(当然,如果您也发布算法,则更好);例如,无论是Dijkstra算法,还是Floyd,或其他什么。

请帮助我,我几个月来一直在考虑这个问题!


我发现这个算法在TOPCODER.COM上 在网格中你只能移动(对角线和向上) 但我无法理解这种算法是什么,任何人都不知道?

#include<iostream>
#include <cmath>

using namespace std;




inline int Calc(int x,int y)

{



if(abs(x)>=abs(y)) return abs(x);
int z=(abs(x)+abs(y))/2;
return z+abs(abs(x)-z);
 }

class SliverDistance
{


    public:
int minSteps(int x1,int y1, int x2, int y2)
{
    int ret=0;
    if(((x1+y1)&1)!=((x2+y2)&1))y1++,ret++;
    return ret+Calc(x2-x1,y2-y1);
}
};

8 个答案:

答案 0 :(得分:38)

Lee的算法:http://en.wikipedia.org/wiki/Lee_algorithm

这实际上是一个BF搜索,这是一个例子:http://www.oop.rwth-aachen.de/documents/oop-2007/sss-oop-2007.pdf

要有效地实施它,请在此处查看我的答案:Change FloodFill-Algorithm to get Voronoi Territory for two data points? - 当我说出标记时,您用来自+ 1的位置上的数字标记它。

例如,如果你有这个网格,其中一个* =障碍,你可以向上,向下,向左和向右移动,你从S开始,必须转到D,0 =自由位置:

S 0 0 0
* * 0 *
* 0 0 *
0 0 * *
* 0 0 D

您将S放入队列中,然后“展开”它:

S 1 0 0
* * 0 *
* 0 0 *
0 0 * *
* 0 0 D

然后展开所有邻居:

S 1 2 0
* * 0 *
* 0 0 *
0 0 * *
* 0 0 D

所有这些邻居的邻居:

S 1 2 3
* * 3 *
* 0 0 *
0 0 * *
* 0 0 D

依此类推,最终你会得到:

S 1 2 3
* * 3 *
* 5 4 *
7 6 * *
* 7 8 9

因此从S到D的距离是9.运行时间是O(NM),其中N =行数,M =列数。我认为这是在网格上实现的最简单的算法,它在实践中也非常有效。它应该比传统的dijkstra更快,虽然如果用堆实现它,dijkstra可能会赢。

答案 1 :(得分:6)

使用A Star (A*)算法。

答案 2 :(得分:5)

您可能会被删除。 Dijkstra算法存在不同的变体。一个计算从每个点到每个其他点的最短路径(如Floyd的)。

但是,典型的Dijkstra算法基于优先级队列,只计算您所需的最短路径。它在执行期间确实构造了几条路径,但这些路径都是从A到可能在最终解决方案路径上的其他节点的部分路径。

因此,您可以轻松地将网格解释为图形(然后可以相应地考虑对角线等限制)并运行Dijkstra搜索从A到B的最短路径。这只是建模问题的问题,而不是你需要一些奇特的算法。

答案 3 :(得分:2)

如果您的移动足够严格(例如,您只能向右或向上移动,或向上和向右移动),那么您可以利用其重叠的子问题和次优的子结构性质并使用dynamic programming

答案 4 :(得分:1)

我不明白的是,如果你想要A和B之间的最短路径,如果 C和D指向你,你还是不需要看A到C和A到D B'你的最短路径很可能是A-C-B或A-D-B。你只需要抛弃未连接的节点。在我的一个项目中,我获取了A点和B点,检查了其他点的连接情况,以及未删除的点数。然后我继续使用Dijkstra的算法。

答案 5 :(得分:1)

这是使用BFS从(0,0)到(0,m-1)的矩阵中的最短路径的python实现。您可以将其更改为适合变量点。

n,m,k1,k2=[int(i) for i in input().split()]
arr=[[int(j) for j in input().split()] for i in range(n)]
x=[[-1 for i in range(m)] for j in range(n)]
x[0][0]=0
vis={}
q=[(0,0)]
while len(q)!=0:
    curr=q[0]
    rem=q.pop(0)
    vis[curr]=True
    r=curr[0]
    c=curr[1]
    if r-1>=0 and arr[r-1][c]==0:
        if vis.get((r-1,c),-1)==-1 or vis[(r-1,c)]!=True:
            q.append((r-1,c))
            x[r-1][c]=x[r][c]+1
    if r+1<n and arr[r+1][c]==0:
        if vis.get((r+1,c),-1)==-1 or vis[(r+1,c)]!=True:
            q.append((r+1,c))
            x[r+1][c]=x[r][c]+1
    if c-1>=0 and arr[r][c-1]==0:
        if vis.get((r,c-1),-1)==-1 or vis[(r,c-1)]!=True:
            q.append((r,c-1))
            x[r][c-1]=x[r][c]+1
    if c+1<m and arr[r][c+1]==0:
        if vis.get((r,c+1),-1)==-1 or vis[(r,c+1)]!=True:
            q.append((r,c+1))
            x[r][c+1]=x[r][c]+1
    #for i in x:
        #print(i)
ans=x[0][m-1]
if ans==-1:
    print(-1)
else:
    print(ans)
  • 输入矩阵应包含0和1。 0表示可能的移动。
  • n是行数。
  • m是列数。
  • arr是给定的矩阵。
  • x是距离(0,0)的距离矩阵。
  • vis是一个字典,如果访问该节点则给出一个布尔值。
  • 输出-1表示没有这样的路径。

答案 6 :(得分:0)

您的网格形成一个图形(或至少可以视为图形)。消除某些运动方向表明它是有向图。如果你不能从一个节点移动到另一个节点,那就是图中没有的边缘。

一旦您将网格编码为图形形式,就可以在众所周知的图形算法(您显然已经意识到)中进行选择,以便根据您想要的结果类型进行遍历(例如,最短的)路径)。

编辑:我看过你发布的答案,但我不确定该代码应该是什么/做什么。例如,它有:if(y>=0) max(abs(x),y);。这似乎(至少对我而言)没有多大意义 - 来自max的结果被简单地抛弃了。要完成一些有用的事情,需要返回或分配该命令。按照目前的情况,您可以希望最好的是编译器将其视为死代码,并且不会为其生成任何内容。

我的猜测是代码并没有真正按预期工作,如果它做了任何有用的事情,那么它比设计更偶然。需要花费大量的时间和精力来确保你已经解决了这样的问题,以至于你确实知道它做了什么,甚至更难以猜出真正意图的是什么。

答案 7 :(得分:-1)

使用A *算法查找2D网格中两点之间的路径。 http://theory.stanford.edu/~amitp/GameProgramming/ImplementationNotes.html