㈠ 图遍历算法之最短路径Dijkstra算法
最短路径问题是图论研究中一个经典算法问题,旨在寻找图中两节点或单个节点到其他节点之间的最短路径。根据问题的不同,算法的具体形式包括:
常用的最短路径算法包括:Dijkstra算法,A 算法,Bellman-Ford算法,SPFA算法(Bellman-Ford算法的改进版本),Floyd-Warshall算法,Johnson算法以及Bi-direction BFS算法。本文将重点介绍Dijkstra算法的原理以及实现。
Dijkstra算法,翻译作戴克斯特拉算法或迪杰斯特拉算法,于1956年由荷兰计算机科学家艾兹赫尔.戴克斯特拉提出,用于解决赋权有向图的 单源最短路径问题 。所谓单源最短路径问题是指确定起点,寻找该节点到图中任意节点的最短路径,算法可用于寻找两个城市中的最短路径或是解决着名的旅行商问题。
问题描述 :在无向图 中, 为图节点的集合, 为节点之间连线边的集合。假设每条边 的权重为 ,找到由顶点 到其余各个节点的最短路径(单源最短路径)。
为带权无向图,图中顶点 分为两组,第一组为已求出最短路径的顶点集合(用 表示)。初始时 只有源点,当求得一条最短路径时,便将新增顶点添加进 ,直到所有顶点加入 中,算法结束。第二组为未确定最短路径顶点集合(用 表示),随着 中顶点增加, 中顶点逐渐减少。
以下图为例,对Dijkstra算法的工作流程进行演示(以顶点 为起点):
注:
01) 是已计算出最短路径的顶点集合;
02) 是未计算出最短路径的顶点集合;
03) 表示顶点 到顶点 的最短距离为3
第1步 :选取顶点 添加进
第2步 :选取顶点 添加进 ,更新 中顶点最短距离
第3步 :选取顶点 添加进 ,更新 中顶点最短距离
第4步 :选取顶点 添加进 ,更新 中顶点最短距离
第5步 :选取顶点 添加进 ,更新 中顶点最短距离
第6步 :选取顶点 添加进 ,更新 中顶点最短距离
第7步 :选取顶点 添加进 ,更新 中顶点最短距离
示例:node编号1-7分别代表A,B,C,D,E,F,G
(s.paths <- shortest.paths(g, algorithm = "dijkstra"))输出结果:
(s.paths <- shortest.paths(g,4, algorithm = "dijkstra"))输出结果:
示例:
找到D(4)到G(7)的最短路径:
[1] 维基网络,最短路径问题: https://zh.wikipedia.org/wiki/%E6%9C%80%E7%9F%AD%E8%B7%AF%E9%97%AE%E9%A2%98 ;
[2]CSDN,Dijkstra算法原理: https://blog.csdn.net/yalishadaa/article/details/55827681 ;
[3]RDocumentation: https://www.rdocumentation.org/packages/RNeo4j/versions/1.6.4/topics/dijkstra ;
[4]RDocumentation: https://www.rdocumentation.org/packages/igraph/versions/0.1.1/topics/shortest.paths ;
[5]Pypi: https://pypi.org/project/Dijkstar/
㈡ 在解决最短路径优化问题中,Dijkstra算法有哪些优.缺点
优点:算法简明、能得到最优解
缺点:效率低(特别是有时候不需要最优解)、运算中占用空间大
㈢ 解释一下dijkstra算法这个计算过程的意思 怎么算的
最近也看到这个算法,不过主要是通过C语言介绍的,不太一样,但基本思想差不多。下面只是我个人的看法不一定准确。
Dijkstra算法主要解决指定某点(源点)到其他顶点的最短路径问题。
基本思想:每次找到离源点最近的顶点,然后以该顶点为中心(过渡顶点),最终找到源点到其余顶点的最短路。
t=1:令源点(v_0)的标号为永久标号(0,λ)(右上角加点), 其他为临时(+无穷,λ). 就是说v_0到v_0的距离是0,其他顶点到v_0的距离为+无穷。t=1时,例5.3上面的步骤(2)(3)并不能体现
t=2:第1步v_0(k=0)获得永久标号,记L_j为顶点标号当前的最短距离(比如v_0标号(0,λ)中L_0=0), 边(v_k,v_j)的权w_kj. 步骤(2)最关键,若v_0与v_j之间存在边,则比较L_k+w_kj与L_j, 而L_k+w_kj=L_0+w_0j<L_j=+无穷。
这里只有v_1,v_2与v_0存在边,所以当j=1,2时修改标号, 标号分别为(L_1, v_0)=(1, v_0), (L_2, v_0)=(4, v_0), 其他不变。步骤(3)比较所有临时标号中L_j最小的顶点, 这里L_1=1最小,v_1获得永久标号(右上角加点)。
t=3: 第2步中v_1获得永久标号(k=1), 同第2步一样,通过例5.3上面的步骤(2)(3),得到永久标号。 步骤(2),若v_1与v_j(j=2,3,4,5(除去获得永久标号的顶点))之间存在边,则比较L_1+w_1j与L_j。这里v_1与v_2,v_3,v_,4存在边,
对于v_2, L_1+w_12=1+2=3<L_2=4, 把v_2标号修改为(L_1+w_12, v_1)=(3, v_1);
对于v_3, L_1+w_13=1+7=8<L_3=+无穷, 把v_3标号修改为(L_1+w_13, v_1)=(8, v_1);
对于v_4, L_1+w_14=1+5=6<L_4=+无穷, 把v_4标号修改为(L_1+w_14, v_1)=(6, v_1);
v_5与v_1不存在边,标号不变。步骤(3), 找这些标号L_j最小的顶点,这里v_2标号最小
t=4: k=2, 与v_2存在边的未获得永久标号的顶点只有v_4, 比较L_2+w_24=3+1=4<L_4=6, 把v_4标号修改为(L_2+w_24, v_2)=(4, v_2); 其他不变。步骤(3), L_4=4最小。
t=5: k=4, 同理先找v_4邻接顶点,比较,修改标号,找L_j最小
t=6: 同理
啰嗦的这么多,其实步骤(2)是关键,就是通过比较更新最短路径,右上角标点的就是距离源点最近的顶点,之后每一步就添加一个新的”源点”,再找其他顶点与它的最短距离。
迪杰斯特拉算法(Dijkstra)(网络):
http://ke..com/link?url=gc_mamV4z7tpxwqju6BoqxVOZ_josbPNcGKtLYJ5GJsJT6U28koc_#4
里面有个动图,更形象地说明了该算法的过程。(其中每次标注的一个红色顶点out就和你的这本书中获得永久标号是相似的)
㈣ 迪杰斯特拉算法的本质是贪心还是动态规划
贪心是一种特殊的动态规划,动态规划的本质是独立的子问题,而贪心则是每次可以找到最优的独立子问题。
贪心和动归不是互斥的,而是包含的,贪心更快,但约束更强,适应范围更小。
动归和bfs的关系也是一样的。
展开一点讲,在求解最优化问题时,有多个解。而求解的过程类似一个树,我们称之为求解树。
一般的求解树真的是一棵树,所以我们只能用bfs来搜索,顶多剪枝。
有些特殊的求解树,中间很多结点是重合的,结点个数比所有搜索分支的个数少很多个数量级。这类问题较特殊,我们可以保存中间的搜索过程。而记忆化搜索和动态规划本质上就是一个东西,快就快在可以不用重复计算很多中间结果(所谓的最优子问题)。
还有一些特殊的求解树,更特殊,它们不止有很多重复结点,而且每次选择分支的时候,我们可以证明只要选择一个分支,这个分支的解就一定比其他选择更优。这类问题就是贪心了,
所以bfs,dp,贪心三个方法都是解决最优化问题的方法,根据问题的不同,约束越大的问题可以用越快的方法,越慢的方法可以解决的问题越普适。
动态规划的状态转移函数,可以抽象成这样一种函数:
f(x)=g(f(x1), f(x2), f(x3), ... f(xn))
其中f就是我们说的独立问题,每个f都有一个唯一值,也就是没有后效性。
贪心也是这个函数,但可以证明:
f(xi) >= f(x1|x2|...|xn)
那么我们就不用再去计算除了f(xi)以外的任何子状态了,所以就更快
而标准的bfs,虽然也有
f(x)=g(f(x1), f(x2), f(x3), ... f(xn))
但是因为对于任意的f(x),它的子问题f(xi)的输入状态xi都不同(换一种思路也可以说f(xi)在不同的路径下值都不同,本质上是我们怎么定义xi,到底是狭义的参数还是广义的状态),所以无法使用内存去换取时间,就只能去遍历所有状态了。
㈤ 迪杰斯特拉算法的介绍
迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。