• "《算法导论》之‘图’":单点最短路径(有向图)


      也许最直观的图处理问题就是你常常需要使用某种地图软件或者导航系统来获取从一个地方到另一个地方的路径。我们立即可以得到与之对应的图模型:顶点对应交叉路口,边对应公路,边的权重对应该路段的成本(时间或距离)。如果有单行线,那就意味着还需要考虑加权有向图。在这个模型中,问题很容易就可以被归纳为:

      找到一个顶点到达另一个顶点的成本最小的路径。

    前言

      单点最短路径指的就是从源点S到给定的目的顶点V的总权重最小的路径。

      从源点S出发,到所有可达的顶点的路径构成了一棵最短路径树(Shortest Path Tree, SPT)。下边显示了从不同源点出发所构成的最短路径树:

      

      本文用到的加权有向图如下:

      

    Dijkstra

    边的松驰

      下图展示了两个边的松驰的操作。在第一个例子中,因为distTo[v] + weght(v, w) > distTo[w],所以认为边v->w应该失效;在第二个例子中,distTo[v] + weght(v, w) < distTo[w],所以认识从其他顶点到w比从v到w的路径要长,原其他顶点到w的路径应该失效,v->w有效。

      通过这两个例子,我们知道,松驰操作的思想跟Prim算法的思想是很相似的。

       

      Java代码:

     1 private void relax(EdgeWeightedDigraph G, int v)
     2 {
     3     for (DirectedEdge e : G.adj(v))
     4     {
     5         int w = e.to();
     6         if (distTo[w] > distTo[v] + e.weight())
     7         {
     8             distTo[w] = distTo[v] + e.weight();
     9             edgeTo[w] = e;
    10         }
    11     }
    12 }

    Dijkstra算法

      在《算法》中给出的Java代码如下:

     1 public class DijkstraSP
     2 {
     3     private DirectedEdge[] edgeTo;
     4     private double[] distTo;
     5     private IndexMinPQ<Double> pq;
     6     public DijkstraSP(EdgeWeightedDigraph G, int s)
     7     {
     8         edgeTo = new DirectedEdge[G.V()];
     9         distTo = new double[G.V()];
    10         pq = new IndexMinPQ<Double>(G.V());
    11         for (int v = 0; v < G.V(); v++)
    12             distTo[v] = Double.POSITIVE_INFINITY;
    13         distTo[s] = 0.0;
    14         pq.insert(s, 0.0);
    15         while (!pq.isEmpty())
    16             relax(G, pq.delMin())
    17     }
    18     private void relax(EdgeWeightedDigraph G, int v)
    19     {
    20         for (DirectedEdge e : G.adj(v))
    21         {
    22             int w = e.to();
    23             if (distTo[w] > distTo[v] + e.weight())
    24             {
    25                 distTo[w] = distTo[v] + e.weight();
    26                 edgeTo[w] = e;
    27                 if (pq.contains(w)) pq.change(w, distTo[w]);
    28                 else pq.insert(w, distTo[w]);
    29             }
    30         }
    31     }
    32     public double distTo(int v) // standard client query methods
    33     public boolean hasPathTo(int v) // for SPT implementatations
    34     public Iterable<Edge> pathTo(int v) // (See page 649.)
    35 }
    View Code

      Dijkstra算法的轨迹如下:

      

      具体代码见Github.

  • 相关阅读:
    PAT乙级1014.福尔摩斯的约会 (20)(20 分)
    PAT乙级1013.数素数
    PAT乙级1012.数字分类 (20)(20 分)
    PAT乙级1011.A+B和C (15)(15 分)
    PAT乙级1025.反转链表 (25)
    PAT乙级1020.月饼(20)
    PAT乙级1015.德才论(25)
    PAT乙级1010.一元多项式求导(25)
    PAT乙级1009.说反话(20)
    PAT乙级1008.数组元素循环右移问题(20)
  • 原文地址:https://www.cnblogs.com/xiehongfeng100/p/4493391.html
Copyright © 2020-2023  润新知