定义

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

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

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. python 切片技巧

    说明: 字符串[开始索引:结束索引:步长] 开始索引:从指定位置开始截取: 结束索引:从指定位置结束截取,但不包含该位置的字符. 步长:不指定时步长为1: 1)当步长为正数时候,那么切片是从左到右进行 ...

  2. python上传文件接口

    1.由于公司做接口测试,遇到了上传文件,一直搞了好久,原来是加了头部的原因def test_79(self): '''导入配置文件''' request = e['mysqlshujuku'] url ...

  3. 洛谷P1086花生采摘(简单模拟)

    题目描述 鲁宾逊先生有一只宠物猴,名叫多多.这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!――熊字”. 鲁宾逊先生和多多都很开心,因为花生正是他 ...

  4. mysql 官方读写分离方案

    mysql 8.0 集群模式下的自动读写分离方案 问题 多主模式下的组复制,看起来挺好,起始问题和限制很多.而且中断一个复制就无法配置了 多主模式下,innodbcluster 等于是无用的,不需要自 ...

  5. Python 爬取 热词并进行分类数据分析-[拓扑数据]

    日期:2020.01.29 博客期:137 星期三 [本博客的代码如若要使用,请在下方评论区留言,之后再用(就是跟我说一声)] 所有相关跳转: a.[简单准备] b.[云图制作+数据导入] c.[拓扑 ...

  6. android的ListAdapter简单用法

    ListAdapter是一个整个Activity有且仅有一个ListView控件的Activity 使用步骤:1. 创建MyListViewAdapter(类名可以自定义) extends ListA ...

  7. Vue学习笔记:v-bind 属性动态绑定

    v-bind 的作用 v-bind指令可以将节点的属性与动态表达式绑定在一起 v-bind可以绑定html元素中的各种属性 例如: <a v-bind:href="xxx"& ...

  8. k种球若干,取n个球,输出所有取球方案 (模拟)

    有K种颜色的小球(K<=10),每种小球有若干个,总数小于100个. 现在有一个小盒子,能放N个小球(N<=8),现在要从这些小球里挑出N个小球,放满盒子. 想知道有哪些挑选方式.注:每种 ...

  9. LeetCode 445. Add Two Numbers II(链表求和)

    题意:两个非空链表求和,这两个链表所表示的数字没有前导零,要求不能修改原链表,如反转链表. 分析:用stack分别存两个链表的数字,然后从低位开始边求和边重新构造链表. Input: (7 -> ...

  10. HTML table表头排序箭头绘制法【不用箭头图片】

    效果图 代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="ut ...