单源最短路径
·找出一个带权有向图从起点到终点权重和最小的路径。
几个变体:
1.单目的地最短路径问题
2.单结点对最短路径问题
3.所有节点对最短路径问题
一个隐藏的重要性质:
两个节点之间的一条最短路径也包含着其它的最短路径,也就是说,最短路径的子路径也是最短路径
一般性,我们可以假定找到的最短路径中没有环路,即他们都是简单路径,由于图G=(V, E)中任意无环路径最多包含|V|个不同的节点,所以它至多包含|V-1|条边。因此最短路径至多是|V-1|。
松弛操作(relaxation)
对一条边(u, v)的松弛过程为:
1.首先测试从起点s到v的最短路径能否改善
方法:将从节点s到节点u之间的最短路径距离加上节点u于v之间的边权重,并于当前s到v的最短路径估计进行比较,如前者更小就更新。
伪代码:
RELAX(u, v, w)
if v.d>u.d+w(u, v)
v.d = u.d + w(u, v)
v.Π=u
解决单源最短路径的两种算法:
Bellman-Ford:解决一般情况下的单源最短路径(边权重可为负值),动态规划
Dijkstra:只能解决边权值为正的情况,贪心,时间复杂度较低。
Bellman-Ford:
给定带权重的有向图G=(V, E)和权重函数w, Bellman-Ford算法返回一个布尔值,表明是否存在一个从源节点可以到达的权重为负值的环路,如果该环路存在,算法告诉我们不存在解决方法,环路不存在,算法返回最短路径以及对应权重。
时间复杂度O(VE)
伪代码:
BELLMAN-FORD(G, w, s)
INIIALIZE-SINGLE-SOURCE(G, s)
for i = 1 to |G.V| - 1
for each edge(u, v)∈G.E
RELAX(u, v, w)
for each edge(u, v)∈G.E
if v.d>u.d+w(u, v)
return FLASE
return TRUE
给定原点是s,初始化时候除了原点s之外,其他的都是无穷大的。因为有5个顶点,所以需要松弛的次数为5-1次
这里我们按照边<t,x>、<t,y>、<t,z>、<y,x>、<y,z>、<z,x>、<z,s>、<s,t>、<s,y>的顺序进行变得松弛操作。第一次按照上述边进行松弛操作之后(实际上只对<s,t>、<s,y>进行操作)的结果为
第二次按照给定边进行松弛操作之后:
第三次松弛操作之后:
最后一次松弛操作:
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
struct edge{
int from;
int to;
double weight;