数据结构 第七讲 图(中)

7.1 最短路径问题

最短路径问题的抽象

在网络中,求两个不同顶点之间的所有路径中,边的权值之和最小的那一条路径。
这条路径就是两点之间的最短路径(Shortest Path)
第一个顶点为源点(Source)
最后一个顶点为终点(Destination)

问题分类

单源最短路径问题:从某固定源点出发,求其到所有其他顶点的最短路径
(有向)无权图
(有向)有权图
多源最短路径问题:求任意两顶点间的最短路径

无权图的单源最短路算法

按照递增(非递减)的顺序找出到各个顶点的最短路
数据结构 第七讲 图(中)

void Unweighted(Vertex S)//以BFS为原型改造的单源无权最短路算法 
{
	Enqueue(S,Q);
	while(!Isempty(Q))
	{
		V = Dequeue(Q);
		for( V的每个邻接点 W )
		{
			if(dist[W] == -1)//如果没有被访问过 
			{
				dist[W] = dist[V] + 1;//初始化源点为0,其他点为-1
				path[W] = V;//记录当前已走过的路径结点,初始化为-1
				Enqueue(W,Q);
			}
		}
	}
}

dist[W] = S 到 W 的最短距离
dist[S] = 0 源点到源点距离为0
path[W] = S 到 W 的路上经过的某顶点
打印路径时顺着path数组一个一个往前推,得到W->S的反向路径,用堆栈来reverse即可
时间复杂度:O( |V| + |E| )

有权图的单源最短路算法

Dijkstra算法

令集合S = {源点s + 已经确定了最短路径的顶点vi}
对任一未收录的顶点v,定义dist[v]为s到v的最短路径长度(不一定是最终的最短路径),但 该路径仅经过S中的顶点。即路径{s->(vi∈S)->v}的最小长度
若路径是按照递增(非递减)的顺序生成的,则
真正的最短路必须只经过S中的顶点
每次从未收录的顶点中选一个dist最小的收录(贪心)
增加一个v进入s,可能影响另外一个w的dist值!(v在s->w的路径上并且v->w一定有一条直接的边)

void Dijkstra(Vertex s)
{
	while(1)
	{
		V = 未收录顶点中dist最小者;
		if(这样的V不存在) break;
		collected[V] = true;
		for( V 的每个邻接点 W )
		{
			if(collected[W]==false)
			{
				if(dist[V]+E<V,W> < dist[W])
				{
					dist[W] = dist[V] + E<V,W>;//初始化源点为0,其他点为+INT_MAX
					path[W] = V; //初始化为-1
				}
			}
		}
	}
}//不能解决有负边的情况 

如何获取未收录顶点中dist最小者
法1:直接扫描所有未收录顶点——O(|V|)
T = O(|V|^2 + |E|)——对于稠密图效果好
法2:将dist存在最小堆中——O(log|V|)
更新 dist[w] 的值——O(log|V|)
T = O( |V|log|V| + |E|log|V| )= O( |E| log|V| )——对于稀疏图效果好

上一篇:【函数分享】每日PHP函数分享(2021-2-26)


下一篇:AcWing 第29场周赛