算法——单源最短路径:Bellman-Ford算法、Dijkstra算法

前言

    在最短路径问题中,约定图是一个带权值的有向图。最短路径是解决两节点之间的最小代价问题。最短路径有几种分类:单源最短路径;单目标最短路径;单节点对最短路径;所有节点对最短路径。下面记录单源最短路径问题。

单源最短路径

定义:

   单源最短路径是给定一个图,希望从一个源节点到每个节点的最短路径。

单源最短路径的算法

    在介绍算法之前,首先必须介绍下松弛操作,在整个算法中,松弛操作是很重要的,松弛操作的目的是要获得最短路径估计;在任何操作之前必须对节点进行初始化操作,松弛过程:将节点到节点之间的最短路径距离加上节点到节点之间的边权值,并与当前节点到节点的最短路径估计进行比较,如果前者较小,则更新最短路径估计和前驱属性。
//初始化操作
INITIALIZE-SINGLE-SOURCE(G,s)
	for each vertex v ∈ G.V 	
		v.d = inf				
		v.front = NIL			
	s.d = 0
//松弛操作
RELAX(u,v,w) //w是权值函数
	if v.d > u.d + w(u,v)
		v.d = u.d + w(u,v)
		v.front = u
松弛操作过程结构:
算法——单源最短路径:Bellman-Ford算法、Dijkstra算法_第1张图片    
    根据对图的边进行不同松弛次数和次序,解决单源最短路径问题,下面介绍两种算法:Bellman-Ford算法和Dijkstra算法。

Bellman-Ford算法

    该算法适用于边权值可为负,但不能有权值为负带有环路的图 因为如果包含环路,且环路的权值和为正的,那么去掉这个环路,可以得到更短的路径;如果环路的权值是负的,那么肯定没有解 。该算法是对每一条边进行次松弛,通过对边的松弛操作渐近地降低从源节点到每个节点的最短路径估计值,直到该估计值与实际的最短路径权重相同为止。若该算法的输入图不包含可以从源节点到达的权重为负值的环路,则返回TRUE。
步骤:
  1. 初始化图的每个节点;
  2. 对每条边进行次松弛操作;
  3. 判断最短路径估计值是否与实际权重相同,若相同则返回TRUE,否则返回FALSE;
//Bellman-Ford算法
BELLMAN-FORD(G,w,s)
	INITIALIZE-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 FALSE
	return TRUE
procedure BellmanFord(list vertices, list edges, vertex source)
   // 该实现读入边和节点的列表,并向两个数组(distance和predecessor)中写入最短路径信息

   // 步骤1:初始化图
   for each vertex v in vertices:
       if v is source then distance[v] := 0
       else distance[v] := infinity
       predecessor[v] := null

   // 步骤2:重复对每一条边进行松弛操作
   for i from 1 to size(vertices)-1:
       for each edge (u, v) with weight w in edges:
           if distance[u] + w < distance[v]:
               distance[v] := distance[u] + w
               predecessor[v] := u

   // 步骤3:检查负权环
   for each edge (u, v) with weight w in edges:
       if distance[u] + w < distance[v]:
           error "图包含了负权环"


举例:算法执行过程中,源节点为 ,图a是初始化后的结果。每一次松弛操作对边的处理次序都是:
,操作的时候记住要按照顺序进行松弛,例如从图a到图b最短路径估计值的变化过程是:第二行:表示初始化结果;第三行:表示按顺序执行完后的结果;第四行:表示执行完的结果;
s t x y z
0
0 6
0 6 7

算法——单源最短路径:Bellman-Ford算法、Dijkstra算法_第2张图片

Dijkstra算法

       Dijkstra 算法要求所有边的权重都为非负。该算法在执行的过程中维持的关键信息是一组节点集合,从源节点到该集合的每个节点之间都是最短路径已被找到。算法重复从节点集合中选择最短路径估计最小的节点,将节点加入到集合,然后对从节点发出的边进行松弛。
//Dijkstra算法
Dijkstra(G,w,s)
	INITIALIZE-SINGLE-SOURCE(G,s)
	S = ∅
	Q = G.V
	while Q ≠ ∅
		u = EXTRACT-MIN(Q)
		S = S ∪{u}
		for each vertex v∈G.Adj[u]
			RELAX(u,v,w)
   举例:执行过程中,刚开始集合为空,则把集合中最短路径估计最小的节点加入到集合 然后对从节点 发出的边进行松弛。
第一步(图b):将节点加入集合,并对节点所发出的边进行松弛操作;
第二步(图c):在集合最短路径估计最小的节点为,将节点加入到集合并对节点所发出的边进行松弛操作;
第三步(图d):在集合最短路径估计最小的节点为,将节点加入到集合,并对节点所发出的边进行松弛操作;
第四步(图e):在集合最短路径估计最小的节点为,将节点加入到集合,并对节点所发出的边进行松弛操作;
第五步(图f):在集合最短路径估计最小的节点为,将节点加入到集合,并对节点所发出的边进行松弛操作;
算法——单源最短路径:Bellman-Ford算法、Dijkstra算法_第3张图片

你可能感兴趣的:(dijkstra算法,单源最短路径,图算法,Bellman-Ford算法)