第四章 图(七) - LeetCode

第四章 图(七)

4.4 最短路径

定义:在一幅加权有向图中,从顶点s到顶点t的最短路径是所有从s到t的路径中的权重最小者。

4.4.1 最短路径的性质

  • 最短路径是有向的
  • 权重不一定等价于距离
  • 并不是所有顶点都是可达的
  • 负权重会使问题更复杂
  • 最短路径一般都是简单的
  • 最短路径不一定是唯一的
  • 可能存在平行边和自环

定义:给定一幅加权有向图和一个顶点s,以s为起点的一棵最短路径树(SPT)是图的一幅子图,它包含s和从s可达的所有顶点。这棵有向树的根结点为s,树的每条路径都是有向图中的一条最短路径。

4.4.2 加权有向图的数据结构

4.4.2.4 边的松弛

  • 最短路径API的实现基于一个被称为松弛的操作
  • 边的松弛技术放松边v->w以为着检查从s到w的最短路径是否是从s先到v,然后在由v到w,如果是则更新数据结构的内容,具体实现如下:
private void relax(DirectedEdge e){
    int v = e.from(), w = e.to();
    if(distTo[w] > distTo[v] + e.weight()){
        distTo[w] = distTo[v] + e.weight();
        edgeTo[w] = e;
    }
}

4.4.2.5 顶点的松弛

  • 实际上,实现会放松从一个给定顶点指出的所有边,具体实现如下:
private void relax(EdgeWeightedDigraph G, int v){
    for(DirectedEdge e : G.adj(v)){
        int w = e.to();
        if(distTo[w] > distTo[v] + e.weight()){
            distTo[w] = distTo[v] + e.weight();
            edgeTo[w] = e;
        }
    }
}

4.4.3 最短路径算法的理论基础

4.4.3.1 最优性条件

最短路径的最优性条件:令G为一幅加权有向图,顶点s是G中的起点,distTo[]是一个由顶点索引的数组,保存的是G中路径的长度。对于从s可达的所有顶点v,distTo[v]的值是从s到v的某条路径的长度,对于从s不可达的所有顶点v,该值为无穷大。当且仅当对于从v到w的任意一条边e,这些值都满足distTo[w]<=distTo[v]+e.weight()时(换句话说,不存在有效边时),它们是最短路径的长度。

  • 以上命题证明了判断路径是否为最短路径的全局条件与在放松一条边时所检测的局部条件是等价的

4.4.3.3 通用算法

通用最短路径算法:将distTo[s]初始化为0,其他distTo[]元素初始化为无穷大,继续如下操作:放松G中的任意边,直到不存在有效边为止。对于任意从s可达的顶点w,在进行这些操作之后,distTo[w]的值即为从s到w的最短路径的长度(且edgeTo[w]的值即为该路径上的最后一条边)。

  • 通用算法并没有指定边的放松顺序

4.4.4 Dijkstra算法

  • 与最小生成树的Prim算法类似,Dijkstra算法将distTo[]最小的非树顶点放松并加入树中,直到所有顶点都在树中,或所有的非树顶点的distTo[]值均为无穷大

Dijkstra算法能够解决边权重非负的加权有向图的单起点最短路径问题。

  • 具体实现如下:
public class DijkstraSP{
    private DirectedEdge[] edgeTo;
    private double[] distTo;
    private IndexMinPQ<double> pq;
    
    public DijkstraSP(EdgeWeightedDigraph G, int s){
        edgeTo = new DirectedEdge[G.V()];
        distTo = new double[G.V()];
        pq = new IndexMinPQ<double>(G.V());
        for(int v = 0; v < G.V(); v++)
            distTo[v] = Double.POSITIVE_INFINITY;
        distTo[s] = 0.0;
        pq.insert(s, 0.0);
        while(!pq.isEmpty())
            relex(G, pq.delMin());
    }
	private void relax(EdgeWeightedDigraph G, int v){
        for(DirectedEdge e : G.adj(v)){
            int w = e.to();
            if(distTo[w] > distTo[v] + e.weight()){
                distTo[w] = distTo[v] + e.weight();
                edgeTo[w] = e;
                if(pq.contaions[w]) pq.change(w, distTo[w]);
                else pq.insert(w, distTo[w]);
            }
        }
    }
}

在一幅含有V个顶点和E条边的加权有向图中,使用Dijkstra算法计算根结点为给定起始点的最短路径树,所需的空间与V成正比,时间与ElogV成正比(最坏情况下)。

posted @ 2021-02-18 22:05  一天到晚睡觉的鱼  阅读(75)  评论(0)    收藏  举报