动态规划(4)详细讲解各最短路径算法及比较

来源:互联网 发布:linux bash profile 编辑:程序博客网 时间:2024/05/18 03:51

1 最短路径问题(The shortest-path problem, SPP)

    最短路径问题是图论研究中的一个经典算法问题,旨在寻找图中两结点之间的最短路径。 算法具体的形式包括:

1) 确定起点的最短路径问题 - 即已知起始结点,求最短路径的问题。

2) 确定终点的最短路径问题 - 与确定起点的问题相反,该问题是已知终结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。

3)确定起点终点的最短路径问题 - 即已知起点和终点,求两结点之间的最短路径。

4)全局最短路径问题 - 求图中所有的最短路径。

    最短路径在导航中有重要应用,如从出发地到目的地的最短路径,从救灾处到受灾处的最短路径等。

各最短路径算法比较


2 Dijkstra(迪杰斯特拉)算法

2.1 定义

    Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。举例来说,如果图中的顶点表示城市,而边上的权重表示著城市间开车行经的距离,该算法可以用来找到两个城市之间的最短路径。

2.2 算法描述

     这个算法是通过为每个顶点 v 保留目前为止所找到的从s到v的最短路径来工作的。初始时,原点 s 的路径长度值被赋为 0 (d[s] = 0),若存在能直接到达的边(s,m),则把d[m]设为w(s,m),同时把所有其他(s不能直接到达的)顶点的路径长度设为无穷大,即表示我们不知道任何通向这些顶点的路径(对于 V 中所有顶点 v 除 s 和上述 m 外 d[v] = ∞)。当算法退出时,d[v] 中存储的便是从 s 到 v 的最短路径,或者如果路径不存在的话是无穷大。 Dijkstra 算法的基础操作是边的拓展:如果存在一条从 u 到 v 的边,那么从 s 到 v 的最短路径可以通过将边(uv)添加到尾部来拓展一条从 s 到 u 的路径。这条路径的长度是 d[u] + w(u, v)。如果这个值比目前已知的 d[v] 的值要小,我们可以用新值来替代当前 d[v] 中的值。拓展边的操作一直运行到所有的 d[v] 都代表从 s 到 v 最短路径的花费。这个算法经过组织因而当d[u] 达到它最终的值的时候每条边(uv)都只被拓展一次。

     算法维护两个顶点集 S 和 Q。集合 S 保留了我们已知的所有 d[v] 的值已经是最短路径的值顶点,而集合 Q 则保留其他所有顶点。集合S初始状态为空,而后每一步都有一个顶点从 Q 移动到 S。这个被选择的顶点是 Q 中拥有最小的 d[u] 值的顶点。当一个顶点 u 从 Q 中转移到了 S 中,算法对每条外接边 (u, v) 进行拓展。

2.2 算法过程图解

以下图为例,具体说明算法的执行过程。


我们将图中的节点分为3类:

1)当前访问的点Current vertex

2) 与当前访问节点相通,但是未访问过的点Fringe vertex

3) 已经访问过的点Visited vertex

为便于图中识别,用下述颜色区分这3种节点:


同时,为了保存当前得到的从开始节点到各个节点的最短路径,我们需要用一个小本本来记录这些值,如下图中的表格(第一行表示各个节点,其下的值代表当前从开始节点到目标节点的最短路径,值后边括号如110(via B)表示到达该节点前要通过的前一个节点是B)。

step 1初始化

从节点A开始,A的Fringe vertex 是B和D(图中inf代表infinite,表示从当前节点到目标节点的路径值还未知,我们设为无穷大)


step 2

get mini in note

从note中获取到达未访问节点的最短路径为当前节点,所以当前节点为B

update distance in note

更新note中从开始点到各个节点的路径,使从开始节点到各个节点的路径最短。具体步骤如下:

1)计算从开始节点到Fringe Vertex的路径(startToFringe),计算公式如下

startToFringe=startToCurrent+ currentToFringe

其中startToCurrent为开始节点到当前节点的路径(该值从note中获得),currentToFringe为当前节点到Frignge节点的路径(该值从原始图中获得)。

当前节点为B,Fringe vertex 为C和D,以Fringe C为例

startToC=startToB+ currentToC=50+60=110

2) 获取Fringe vertex 在note中的路径( fringeInNoteDist)

以Fringe C为例,CInNoteDist=inf

3)比较startToFringe和 fringeInNoteDist,如果startToFringe< fringeInNoteDis,则更新note中的Fringe vertex的值为startToFringe,并修改其前一个经由的节点为当前点。

因为startToC<CInNoteDist,所以note中到达C的值为110(B)

同样,对Fringe D,做同样的计算:

startToD=startToB+currentToD=50+90=140

DInNoteDist=80

startToD>DInNoteDist,所以D在note中的值不变

step 3

get mini in note
从note中获取到达未访问节点的最短路径为当前节点,所以当前节点为D
update distance in note
更新note中从开始点到各个点的路径,使从开始点到各个点的路径最短。具体步骤如下:
1)计算从开始点到Fringe Vertex的路径(startToFringe),计算公式如下
startToFringe=startToCurrent+ currentToFringe
其中startToCurrent为开始点到当前点的路径,currentToFringe为当前点到Frignge点的路径。
当前点为D,Fringe vertex 为C和E,以Fringe C为例
startToC=startToD+ currentToC=80+20=100
2) 获取Fringe vertex 在note中的路径( fringeInNoteDist)
以Fringe C为例,CInNoteDist=110
3)比较startToFringe和 fringeInNoteDist,如果startToFringe< fringeInNoteDis,则更新note中的Fringe vertex的值为startToFringe,并修改其前一个经由的节点为当前点。
因为startToC<CInNoteDist,所以note中到达C的值为100(D)
同样,对Fringe E,做同样的计算:
startToE=startToD+currentToE=80+70=150
DInNoteDist=inf
startToD<DInNoteDist
,所以note中到达E的值为150(D)


step4

get mini in note
从note中获取到达未访问节点的最短路径为当前节点,所以当前节点为C
update distance in note
更新note中从开始点到各个点的路径,使从开始点到各个点的路径最短。具体步骤如下:
1)计算从开始点到Fringe Vertex的路径(startToFringe),计算公式如下
startToFringe=startToCurrent+ currentToFringe
其中startToCurrent为开始点到当前点的路径,currentToFringe为当前点到Frignge点的路径。
当前点为C,Fringe vertex 为E,以Fringe E为例
startToE=startToC+ currentToE=100+40=140
2) 获取Fringe vertex 在note中的路径( fringeInNoteDist)
以Fringe E为例,EInNoteDist=150
3)比较startToFringe和 fringeInNoteDist,如果startToFringe< fringeInNoteDis,则更新note中的Fringe vertex的值为startToFringe,并修改其前一个经由的节点为当前点。
因为startToE<EInNoteDist,所以note中到达E的值为140(C)


step5

从note中获取到达未访问节点的最短路径为当前节点,所以当前节点为E,但是图中没有未访问过的点,及其他点都已经访问过,如下图


因此,E为最后一个点,因此将E标识为已访问过的点,至此算法结束


最后,note中得到的值是从开始点到各个点的最短路径。

2.3 算法实现

2.3.1 算法主框架设计

我们看到上述算法过程,主要是以下3个步骤:

1)initial初始化

选择开始节点,初始化小本本note中的值。

2)get mini in note 获取下一个当前节点

从note中获取到达未访问节点的最短路径的节点为当前节点,有点拗口,这样说吧,即获取当前note中未访问节点中有最小值的那个。

3)update distance in note

更新note中未访问节点的值,使这个值最小(要记住,这个值代表从开始节点到该节点的当前最短路径。)

具体步骤如下:
1)计算从开始节点到Fringe Vertex的路径(startToFringe),计算公式如下
startToFringe=startToCurrent+ currentToFringe
其中startToCurrent为开始节点到当前节点的路径(该值从note中获得),currentToFringe为当前节点到Frignge节点的路径(该值从原始图中获得)。

2) 获取Fringe vertex 在note中的路径( fringeInNoteDist)

3)比较startToFringe和 fringeInNoteDist,如果startToFringe< fringeInNoteDis,则更新note中的Fringe vertex的值为startToFringe,并修改其前一个经由的节点为当前点。
因为startToC<CInNoteDist,所以note中到达C的值为110(B)

算法什么时候结束呢?重复上述步骤2和3直到所有的节点都访问过结束。

要实现该算法,结合上述算法过程,需要解决如下问题:

1)上图中的3类节点在代码中如何表示

Fringe vertex可以从图的邻接矩阵或邻接链表中获得, Current vertex 从小本本note中获得, un-visited vertex可以在节点中加入属性(如isInTree)来标识。

2)小本本note如何表示?

小本本可以用数组或优先队列来实现,小本本中的值可以用以下对象进行抽象:

[java] view plaincopy
  1. <span style="font-size:18px">class DistPar             // distance and parent  
  2.    {                      // items stored in sPath array  
  3.    public int distance;   // distance from start to this vertex  
  4.    public int parentVert; // current parent of this vertex  
  5. // -------------------------------------------------------------  
  6.    public DistPar(int pv, int d)  // constructor  
  7.       {  
  8.       distance = d;  
  9.       parentVert = pv;  
  10.       }  
  11. // -------------------------------------------------------------  
  12.    }  // end class DistPar</span>  


根据上述过程,算法主框架实现如下:

[java] view plaincopy
  1. <span style="font-size:18px">// -------------------------------------------------------------  
  2.    public void path()                // find all shortest paths  
  3.       {      
  4.       //1 initial  
  5.       int currentVerIndex = 0;             // start at vertex 0  
  6.       vertexList[currentVerIndex].isInTree = true;  //isInTree records whether the vertex's visited  
  7.       nTree = 1;                           // record how many vertices has been visited  
  8.   
  9.       // transfer row of distances from adjMat to sPath  
  10.       for(int j=0; j<nVerts; j++)  
  11.          {  
  12.          int tempDist = adjMat[currentVerIndex][j];  
  13.          sPath[j] = new DistPar(currentVerIndex, tempDist);  //sPath is the note, here represent as an array  
  14.          }  
  15.   
  16.       while(nTree < nVerts)   //base case: until all vertices are in the tree  
  17.          {  
  18.             //2 get minimum from sPath  
  19.             currentVerIndex = getMin();    
  20.             //3 update path  
  21.             updatePath(currentVerIndex);  
  22.          }  // end while(nTree<nVerts)  
  23.   
  24.       displayPaths();                // display sPath[] contents  
  25.   
  26.       nTree = 0;                     // clear tree  
  27.       for(int j=0; j<nVerts; j++)  
  28.          vertexList[j].isInTree = false;  
  29.       }  // end path()  
  30.   
  31. </span>  

2.3.2 具体实现

上述方法       //2 get minimum from sPath
            currentVerIndex = getMin();  
            //3 update path
            updatePath(currentVerIndex);

具体实现如下:

[java] view plaincopy
  1. <span style="font-size:18px">// -------------------------------------------------------------  
  2.    public int getMin()               // get entry from sPath  
  3.       {                              //    with minimum distance  
  4.       int minDist = INFINITY;        // assume minimum  
  5.       int indexMin = 0;  
  6.       for(int j=1; j<nVerts; j++)    // for each vertex,  
  7.          {                           // if it's in tree and  
  8.          if( !vertexList[j].isInTree &&  // smaller than old one  
  9.                                sPath[j].distance < minDist )  
  10.             {  
  11.             minDist = sPath[j].distance;  
  12.             indexMin = j;            // update minimum  
  13.             }  
  14.          }  // end for  
  15.       return indexMin;               // return index of minimum  
  16.       }  // end getMin()</span>  
[java] view plaincopy
  1. <span style="font-size:18px">// -------------------------------------------------------------  
  2.    public void updatePath()  
  3.       {  
  4.       // adjust values in shortest-path array sPath  
  5.       int column = 1;                // skip starting vertex  
  6.       while(column < nVerts)         // go across columns  
  7.          {  
  8.          // if this column's vertex already in tree, skip it  
  9.          if( vertexList[column].isInTree )  
  10.             {  
  11.             column++;  
  12.             continue;  
  13.             }  
  14.          // calculate distance for one sPath entry  
  15.                        // get edge from currentVert to column  
  16.          int currentToFringe = adjMat[currentVert][column];  
  17.                        // add distance from start  
  18.          int startToFringe = startToCurrent + currentToFringe;  
  19.                        // get distance of current sPath entry  
  20.          int sPathDist = sPath[column].distance;  
  21.   
  22.          // compare distance from start with sPath entry  
  23.          if(startToFringe < sPathDist)   // if shorter,  
  24.             {                            // update sPath  
  25.             sPath[column].parentVert = currentVert;  
  26.             sPath[column].distance = startToFringe;  
  27.             }  
  28.          column++;  
  29.          }  // end while(column < nVerts)  
  30.    }  // end adjust_sPath()</span>  

2.3.3 全部算法代码

[java] view plaincopy
  1. <span style="font-size:18px">// path.java  
  2. // demonstrates shortest path with weighted, directed graphs  
  3. // to run this program: C>java PathApp  
  4. ////////////////////////////////////////////////////////////////  
  5. class DistPar             // distance and parent  
  6.    {                      // items stored in sPath array  
  7.    public int distance;   // distance from start to this vertex  
  8.    public int parentVert; // current parent of this vertex  
  9. // -------------------------------------------------------------  
  10.    public DistPar(int pv, int d)  // constructor  
  11.       {  
  12.       distance = d;  
  13.       parentVert = pv;  
  14.       }  
  15. // -------------------------------------------------------------  
  16.    }  // end class DistPar  
  17. ///////////////////////////////////////////////////////////////  
  18. class Vertex  
  19.    {  
  20.    public char label;        // label (e.g. 'A')  
  21.    public boolean isInTree;  
  22. // -------------------------------------------------------------  
  23.    public Vertex(char lab)   // constructor  
  24.       {  
  25.       label = lab;  
  26.       isInTree = false;  
  27.       }  
  28. // -------------------------------------------------------------  
  29.    }  // end class Vertex  
  30. ////////////////////////////////////////////////////////////////  
  31. class Graph  
  32.    {  
  33.    private final int MAX_VERTS = 20;  
  34.    private final int INFINITY = 1000000;  
  35.    private Vertex vertexList[]; // list of vertices  
  36.    private int adjMat[][];      // adjacency matrix  
  37.    private int nVerts;          // current number of vertices  
  38.    private int nTree;           // number of verts in tree  
  39.    private DistPar sPath[];     // array for shortest-path data  
  40.    private int currentVert;     // current vertex  
  41.    private int startToCurrent;  // distance to currentVert  
  42. // -------------------------------------------------------------  
  43.    public Graph()               // constructor  
  44.       {  
  45.       vertexList = new Vertex[MAX_VERTS];  
  46.                                          // adjacency matrix  
  47.       adjMat = new int[MAX_VERTS][MAX_VERTS];  
  48.       nVerts = 0;  
  49.       nTree = 0;  
  50.       for(int j=0; j<MAX_VERTS; j++)     // set adjacency  
  51.          for(int k=0; k<MAX_VERTS; k++)  //     matrix  
  52.             adjMat[j][k] = INFINITY;     //     to infinity  
  53.       sPath = new DistPar[MAX_VERTS];    // shortest paths  
  54.       }  // end constructor  
  55. // -------------------------------------------------------------  
  56.    public void addVertex(char lab)  
  57.       {  
  58.       vertexList[nVerts++] = new Vertex(lab);  
  59.       }  
  60. // -------------------------------------------------------------  
  61.    public void addEdge(int start, int end, int weight)  
  62.       {  
  63.       adjMat[start][end] = weight;  // (directed)  
  64.       }  
  65. // -------------------------------------------------------------  
  66.    // find all shortest paths  
  67.    public void path(){  
  68.       //step1 initial  
  69.       int startTree = 0;             // start at vertex 0  
  70.       vertexList[startTree].isInTree = true;  //isInTree records whether the vertex's visited  
  71.       nTree = 1;                     //record how many vertices has been visited  
  72.   
  73.       // transfer row of distances from adjMat to sPath  
  74.       for(int j=0; j<nVerts; j++){  
  75.          int tempDist = adjMat[startTree][j];  
  76.          sPath[j] = new DistPar(startTree, tempDist);  //sPath is the note, here represent as an array  
  77.          }  
  78.   
  79.       while(nTree < nVerts)  {  //base case: until all vertices are in the tree  
  80.          //step2 get minimum from sPath  
  81.          int indexMin = getMin();     
  82.          int minDist = sPath[indexMin].distance;  
  83.            
  84.          //special case: if all infinite or in tree,sPath is complete  
  85.          if(minDist == INFINITY)  {                          
  86.             System.out.println("There are unreachable vertices");  
  87.             break;                     
  88.             }  
  89.          else{                        // reset currentVert  
  90.             currentVert = indexMin;  // to closest vert  
  91.             // minimum distance from startTree is to currentVert, and is startToCurrent  
  92.             startToCurrent = sPath[indexMin].distance;  
  93.             }  
  94.          // put current vertex in tree  
  95.          vertexList[currentVert].isInTree = true;  
  96.          nTree++;  
  97.            
  98.          //step3 update path  
  99.          updatePath();             // update sPath[] array  
  100.          }  // end while(nTree<nVerts)  
  101.   
  102.         //step4 printout all shortest path  
  103.         displayPaths();                // display sPath[] contents  
  104.   
  105.       nTree = 0;                     // clear tree  
  106.       for(int j=0; j<nVerts; j++)  
  107.          vertexList[j].isInTree = false;  
  108.       }  // end path()  
  109. // -------------------------------------------------------------  
  110.    public int getMin()               // get entry from sPath  
  111.       {                              //    with minimum distance  
  112.       int minDist = INFINITY;        // assume minimum  
  113.       int indexMin = 0;  
  114.       for(int j=1; j<nVerts; j++)    // for each vertex,  
  115.          {                           // if it's in tree and  
  116.          if( !vertexList[j].isInTree &&  // smaller than old one  
  117.                                sPath[j].distance < minDist )  
  118.             {  
  119.             minDist = sPath[j].distance;  
  120.             indexMin = j;            // update minimum  
  121.             }  
  122.          }  // end for  
  123.       return indexMin;               // return index of minimum  
  124.       }  // end getMin()  
  125. // -------------------------------------------------------------  
  126.    public void updatePath()  
  127.       {  
  128.       // adjust values in shortest-path array sPath  
  129.       int column = 1;                // skip starting vertex  
  130.       while(column < nVerts)         // go across columns  
  131.          {  
  132.          // if this column's vertex already in tree, skip it  
  133.          if( vertexList[column].isInTree )  
  134.             {  
  135.             column++;  
  136.             continue;  
  137.             }  
  138.          // calculate distance for one sPath entry  
  139.                        // get edge from currentVert to column  
  140.          int currentToFringe = adjMat[currentVert][column];  
  141.                        // add distance from start  
  142.          int startToFringe = startToCurrent + currentToFringe;  
  143.                        // get distance of current sPath entry  
  144.          int sPathDist = sPath[column].distance;  
  145.   
  146.          // compare distance from start with sPath entry  
  147.          if(startToFringe < sPathDist)   // if shorter,  
  148.             {                            // update sPath  
  149.             sPath[column].parentVert = currentVert;  
  150.             sPath[column].distance = startToFringe;  
  151.             }  
  152.          column++;  
  153.          }  // end while(column < nVerts)  
  154.    }  // end adjust_sPath()  
  155. // -------------------------------------------------------------  
  156.    public void displayPaths()  
  157.       {  
  158.       for(int j=0; j<nVerts; j++) // display contents of sPath[]  
  159.          {  
  160.          System.out.print(vertexList[j].label + "="); // B=  
  161.          if(sPath[j].distance == INFINITY)  
  162.             System.out.print("inf");                  // inf  
  163.          else  
  164.             System.out.print(sPath[j].distance);      // 50  
  165.          char parent = vertexList[ sPath[j].parentVert ].label;  
  166.          System.out.print("(" + parent + ") ");       // (A)  
  167.          }  
  168.       System.out.println("");  
  169.       }  
  170. // -------------------------------------------------------------  
  171.    }  // end class Graph  
  172. ////////////////////////////////////////////////////////////////  
  173. class PathApp  
  174.    {  
  175.    public static void main(String[] args)  
  176.       {  
  177.       Graph theGraph = new Graph();  
  178.       theGraph.addVertex('A');     // 0  (start)  
  179.       theGraph.addVertex('B');     // 1  
  180.       theGraph.addVertex('C');     // 2  
  181.       theGraph.addVertex('D');     // 3  
  182.       theGraph.addVertex('E');     // 4  
  183.   
  184.       theGraph.addEdge(0150);  // AB 50  
  185.       theGraph.addEdge(0380);  // AD 80  
  186.       theGraph.addEdge(1260);  // BC 60  
  187.       theGraph.addEdge(1390);  // BD 90  
  188.       theGraph.addEdge(2440);  // CE 40  
  189.       theGraph.addEdge(3220);  // DC 20  
  190.       theGraph.addEdge(3470);  // DE 70  
  191.       theGraph.addEdge(4150);  // EB 50  
  192.   
  193.       System.out.println("Shortest paths");  
  194.       theGraph.path();             // shortest paths  
  195.       System.out.println();  
  196.       }  // end main()  
  197.    }  // end class PathApp  
  198. ////////////////////////////////////////////////////////////////  
  199. </span>  

注:代码来自于书《Data Structure & Algorithm in JAVA》

Floyd-Warshall算法(动态规划)

是解决任意两点间的最短路径的一种算法,时间复杂度为O(N^3),空间复杂度为O(N^2)。可以正确处理有向图或负权的最短路径问题。
设 dist(i,j) 为从节点i到节点j的最短距离
若最短路径经过点k,则dist(i,j)=dist(i,k) + dist(k,j),将该路径与先前的dist(i,j)比较获取最小值,即
dist(i,j)=min( dist(i,k) + dist(k,j) ,dist(i,j) )
Floyd-Warshall算法的描述如下:

[java] view plaincopy
  1. <span style="font-size:18px">//根据图的邻接矩阵,或邻接链表,初始化dist(i,j)  
  2. //其中dist(i,j)表示由点i到点j的代价,当dist(i,j)为 inf 表示两点之间没有任何连接。  
  3. For i←1 to n do  
  4.    For j←1 to n do  
  5.       dist(i,j) = weight(i,j)   
  6. //计算最短路径        
  7. for k ← 1 to n do  
  8.   for i ← 1 to n do  
  9.     for j ← 1 to n do  
  10.         if (dist(i,k) + dist(k,j) < dist(i,j)) then // 是否是更短的路径?  
  11.             dist(i,j) = dist(i,k) + dist(k,j)</span>  

Bellman-Ford(动态规划)

求单源最短路,可以判断有无负权回路(若有,则不存在最短路),时效性较好,时间复杂度O(VE)。
step1:初始化dist(i),除了初始点的值为0,其余都为infinit(表示无穷大,不可到达),pred表示经过的前一个顶点
step2:执行n-1(n等于图中点的个数)次松弛计算:dist(j)=min( dist(i)+weight(i,j),dist(j) )
step3:再重复操作一次,如国dist(j) > distdist(i)+weight(i,j)表示途中存在从源点可达的权为负的回路。
因为,如果存在从源点可达的权为负的回路,则应为无法收敛而导致不能求出最短路径。 
因为负权环可以无限制的降低总花费,所以如果发现第n次操作仍可降低花销,就一定存在负权环。

[java] view plaincopy
  1. int[] dist=new int[n];  
  2. int[] pre=new int[n];  
  3.   
  4. public void Bellman_Ford(){  
  5.   //初始化  
  6.   for(int i=1;i<n-1;i++){  
  7.      dist[i]=infinit; //TODO  
  8.   }//end for  
  9.       
  10.   dist[s]=0 //起始点的值    
  11.     
  12.   for (int i=1;i<=n-1;i++){  
  13.     for(int j=1;j<=edgenum; j++){  
  14.       if(dist(i)+weight(i,j) <dist(j) ){  
  15.          dist(j)=dist(i)+weight(i,j);  
  16.          pred(j)=i;  
  17.       }//end if  
  18.     }//end for  
  19.   }//end for  
  20.     
  21.   //  
  22.   for(int j=1;j<=edgenum;j++){  
  23.      if(dist(i)+weight(i,j)<dist()j )  
  24.         return "有负权回路,不存在最短路径";  
  25.   }//end for  
  26.     
  27. }//end Bellman_Ford()  

A*算法

A*搜寻算法,俗称A星算法,作为启发式搜索算法中的一种,这是一种在图形平面上,有多个节点的路径,求出最低通过成本的算法。
常用于游戏中的NPC的移动计算,或线上游戏的BOT的移动计算上。该算法像Dijkstra算法一样,可以找到一条最短路径;也像BFS一样,进行启发式的搜索。

详细见http://blog.csdn.net/v_JULY_v/article/details/6093380

次最短路径

将最短路径中边在图中去掉,然后再求一次最小生成树

其他

【google笔试题】,一个环形公路,给出相邻两点的距离(一个数组),让你求任意两点的最短距离,要求空间复杂度不超过O(N)

0 0