定义

所谓最短路径问题是指:如果从图中某一顶点(源点)到达另一顶点(终点)的路径可能不止一条,如何找到一条路径使得沿此路径上各边的权值总和(称为路径长度)达到最小。

下面我们介绍两种比较常用的求最短路径算法:

Dijkstra(迪杰斯特拉)算法

他的算法思想是按路径长度递增的次序一步一步并入来求取,是贪心算法的一个应用,用来解决单源点到其余顶点的最短路径问题。

算法思想

首先,我们引入一个辅助向量D,它的每个分量D[i]表示当前找到的从起始节点v到终点节点vi的最短路径的长度。它的初始态为:若从节点v到节点vi有弧,则D[i]为弧上的权值,否则D[i]为∞,显然,长度为D[j] = Min{D[i] | vi ∈V}的路径就是从v出发最短的一条路径,路径为(v, vi)。

那么,下一条长度次短的最短路径是哪一条呢?假设次短路径的终点是vk,则可想而知,这条路径或者是(v, vk)或者是(v, vj, vk)。它的长度或者是从v到vk的弧上的权值,或者是D[j]和从vj到vk的权值之和。

因此下一条次短的最短路径的长度是:D[j] = Min{D[i] | vi ∈ V - S},其中,D[i]或者是弧(v, vi)的权值,或者是D[k](vk ∈ S)和弧(vk, vi)上权值之和。

算法描述

假设现要求取如下示例图所示的顶点V0与其余各顶点的最短路径:

我们使用Guava的ValueGraph作为该图的数据结构,每个顶点对应一个visited变量来表示节点是在V中还是在S中,初始时S中只有顶点V0。然后,我们看看新加入的顶点是否可以到达其他顶点,并且看看通过该顶点到达其他点的路径长度是否比从V0直接到达更短,如果是,则修改这些顶点的权值(即if (D[j] + arcs[j][k] < D[k]) then D[k] = D[j] + arcs[j][k])。然后又从{V - S}中找最小值,重复上述动作,直到所有顶点都并入S中。

第一步,我们通过ValueGraphBuilder构造图的实例,并输入边集:

MutableValueGraph<String, Integer> graph = ValueGraphBuilder.directed()
.nodeOrder(ElementOrder.insertion())
.expectedNodeCount(10)
.build();
graph.putEdgeValue(V0, V2, 10);
graph.putEdgeValue(V0, V4, 30);
graph.putEdgeValue(V0, V5, 100);
graph.putEdgeValue(V1, V2, 5);
graph.putEdgeValue(V2, V3, 50);
graph.putEdgeValue(V3, V5, 10);
graph.putEdgeValue(V4, V3, 20);
graph.putEdgeValue(V4, V5, 60); return graph;

初始输出结果如下:

nodes: [v0, v2, v4, v5, v1, v3],
edges: {<v0 -> v5>=100, <v0 -> v4>=30, <v0 -> v2>=10,
<v2 -> v3>=50, <v4 -> v5>=60, <v4 -> v3>=20, <v1 -> v2>=5,
<v3 -> v5>=10}

为了不破坏graph的状态,我们引入一个临时结构来记录每个节点运算的中间结果:

private static class NodeExtra {
public String nodeName; //当前的节点名称
public int distance; //开始点到当前节点的最短路径
public boolean visited; //当前节点是否已经求的最短路径(S集合)
public String preNode; //前一个节点名称
public String path; //路径的所有途径点
}

第二步,我们首先将起始点V0并入集合S中,因为他的最短路径已知为0:

startNode = V0;
NodeExtra current = nodeExtras.get(startNode);
current.distance = 0; //一开始可设置开始节点的最短路径为0
current.visited = true; //并入S集合
current.path = startNode;
current.preNode = startNode;

第三步,在当前状态下找出起始点V0开始到其他节点路径最短的节点:

NodeExtra minExtra = null; //路径最短的节点信息
int min = Integer.MAX_VALUE;
for (String notVisitedNode : nodes) {
//获取节点的辅助信息
NodeExtra extra = nodeExtras.get(notVisitedNode); //不在S集合中,且路径较短
if (!extra.visited && extra.distance < min) {
min = extra.distance;
minExtra = extra;
}
}

第四步,将最短路径的节点并入集合S中:

if (minExtra != null) { //找到了路径最短的节点
minExtra.visited = true; //并入集合S中
//更新其中转节点路径
minExtra.path = nodeExtras.get(minExtra.preNode).path + " -> " + minExtra.nodeName;
current = minExtra; //标识当前并入的最短路径节点
}

第五步,更新与其相关节点的最短路径中间结果:

/**
* 并入新查找到的节点后,更新与其相关节点的最短路径中间结果
* if (D[j] + arcs[j][k] < D[k]) D[k] = D[j] + arcs[j][k]
*/
//只需循环当前节点的后继列表即可(优化)
Set<String> successors = graph.successors(current.nodeName);
for (String notVisitedNode : successors) {
NodeExtra extra = nodeExtras.get(notVisitedNode);
if (!extra.visited) {
final int value = current.distance
+ graph.edgeValueOrDefault(current.nodeName,
notVisitedNode, 0); //D[j] + arcs[j][k]
if (value < extra.distance) { //D[j] + arcs[j][k] < D[k]
extra.distance = value;
extra.preNode = current.nodeName;
}
}
}

第六步,输出起始节点V0到每个节点的最短路径以及路径的途径点信息

Set<String> keys = nodeExtras.keySet();
for (String node : keys) {
NodeExtra extra = nodeExtras.get(node);
if (extra.distance < Integer.MAX_VALUE) {
Log.i(TAG, startNode + " -> " + node + ": min: " + extra.distance
+ ", path: " + extra.path); //path在运算过程中更新
}
}

实例图的输出结果为:

 v0 -> v0: min: 0, path: v0
v0 -> v2: min: 10, path: v0 -> v2
v0 -> v3: min: 50, path: v0 -> v4 -> v3
v0 -> v4: min: 30, path: v0 -> v4
v0 -> v5: min: 60, path: v0 -> v4 -> v3 -> v5

具体Dijkstra算法的示例demo实现,请参考:

https://github.com/Jarrywell/GH-Demo/blob/master/app/src/main/java/com/android/test/demo/graph/Dijkstra.java

最短路径问题:Dijkstra算法的更多相关文章

  1. 单源最短路径(dijkstra算法)php实现

    做一个医学项目,当中在病例评分时会用到单源最短路径的算法.单源最短路径的dijkstra算法的思路例如以下: 如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点.那么( ...

  2. 【算法设计与分析基础】25、单起点最短路径的dijkstra算法

    首先看看这换个数据图 邻接矩阵 dijkstra算法的寻找最短路径的核心就是对于这个节点的数据结构的设计 1.节点中保存有已经加入最短路径的集合中到当前节点的最短路径的节点 2.从起点经过或者不经过 ...

  3. 数据结构与算法--最短路径之Dijkstra算法

    数据结构与算法--最短路径之Dijkstra算法 加权图中,我们很可能关心这样一个问题:从一个顶点到另一个顶点成本最小的路径.比如从成都到北京,途中还有好多城市,如何规划路线,能使总路程最小:或者我们 ...

  4. 最短路径 | 深入浅出Dijkstra算法(一)

    参考网址: https://www.jianshu.com/p/8b3cdca55dc0 写在前面: 上次我们介绍了神奇的只有五行的 Floyd-Warshall 最短路算法,它可以方便的求得任意两点 ...

  5. 经典树与图论(最小生成树、哈夫曼树、最短路径问题---Dijkstra算法)

    参考网址: https://www.jianshu.com/p/cb5af6b5096d 算法导论--最小生成树 最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树. im ...

  6. ACM: HDU 3790 最短路径问题-Dijkstra算法

    HDU 3790 最短路径问题 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Des ...

  7. python数据结构与算法——图的最短路径(Dijkstra算法)

    # Dijkstra算法——通过边实现松弛 # 指定一个点到其他各顶点的路径——单源最短路径 # 初始化图参数 G = {1:{1:0, 2:1, 3:12}, 2:{2:0, 3:9, 4:3}, ...

  8. 最短路径问题——dijkstra算法

    仅谈谈个人对dijkstra的理解,dijkstra算法是基于邻接表实现的,用于处理单源最短路径问题(顺便再提一下,处理单源最短路径问题的还有bellman算法).开辟一个结构体,其变量为边的终点和边 ...

  9. 最短路径之Dijkstra算法及实例分析

    Dijkstra算法迪科斯彻算法 Dijkstra算法描述为:假设用带权邻接矩阵来表示带权有向图.首先引进一个辅助向量D,它的每个分量D[i]表示当前所找到的从始点v到每个终点Vi的最短路径.它的初始 ...

  10. HDU1548——A strange lift(最短路径:dijkstra算法)

    A strange lift DescriptionThere is a strange lift.The lift can stop can at every floor as you want, ...

随机推荐

  1. 【知识学习】PHP实现批量替换字典后缀

    <?php //要打开字典的物理路径 $filename = 'E:\Local Test\WWW\password.txt'; $handle = fopen($filename,'r') o ...

  2. Codeforce 977E Cyclic Components

    dfs判断图的连通块数量~ #include<cstdio> #include<algorithm> #include<vector> #include<cs ...

  3. WLC RTU license

    目前思科的某些WLC不是一定要license文件去安装,例如这里提到的RTU license. RTU:Right To Use Right to Use (RTU) licensing is a m ...

  4. 使用vASA842配置ASDM645

    准备:使用VMware打开vASA842.ova文件,将第一个网络适配器桥接到一个vmnet接口,我这里是vmnet3,网段是10.0.0.0/24,网关是10.0.0.1/24 1.打开vASA84 ...

  5. Codeforces Round #619 (Div. 2) B. Motarack's Birthday

    Dark is going to attend Motarack's birthday. Dark decided that the gift he is going to give to Motar ...

  6. Website's Game source code

    A Darkroom by doublespeakgames <!DOCTYPE html> <html itemscope itemtype="https://schem ...

  7. leetCode练题——21. Merge Two Sorted Lists(照搬大神做法)

    1.题目 21. Merge Two Sorted Lists Merge two sorted linked lists and return it as a new list. The new l ...

  8. 「NOI2009」植物大战僵尸

    「NOI2009」植物大战僵尸 传送门 这是一道经典的最大权闭合子图问题,可以用最小割解决(不会的可以先自学一下) 具体来说,对于这道题,我们对于两个位置的植物 \(i\) 和 \(j\) ,如果 \ ...

  9. JavaScript - Compiling Vs Transpiling

    参考 https://blog.csdn.net/napolunyishi/article/details/20473799 https://www.stevefenton.co.uk/2012/11 ...

  10. spark实验(一)--linux系统常见命令及其文件互传(2)

    2.使用 Linux 系统的常用命令 启动 Linux 虚拟机,进入 Linux 系统,通过查阅相关 Linux 书籍和网络资料,或者参考 本教程官网的“实验指南”的“Linux 系统常用命令”,完成 ...