最短路问题(整理版)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
最短路问题(short-path problem)
若网络中的每条边都有一个权值值(长度、成本、时间等),则找出两节点(通常是源节点与结束点)之间总权和最小的路径就是最短路问题。最短路问题是网络理论解决的典型问题之一,可用来解决管路铺设、线路安装、厂区布局和设备更新等实际问题。最短路问题,我们通常归属为三类:单源最短路径问题(确定起点或确定终点的最短路径问题)、确定起点终点的最短路径问题(两节点之间的最短路径)
1、Dijkstra算法:
用邻接矩阵a表示带权有向图,d为从v0出发到图上其余各顶点可能达到的最短路径长度值,以v0为起点做一次dijkstra,便可以求出从结点v0到其他结点的最短路径长度
代码:
procedure dijkstra(v0:longint);//v0为起点做一次dijkstra
begin//a数组是邻接矩阵,a[i,j]表示i到j的距离,无边就为maxlongint
for i:=1 to n do d[i]:=a[v0,i];//初始化d数组(用于记录从v0到结点i的最短路径), fillchar(visit,sizeof(visit),false);//每个结点都未被连接到路径里
visit[v0]:=true;//已经连接v0结点
for i:=1 to n-1 do//剩下n-1个节点未加入路径里;
begin
min:=maxlongint;//初始化min
for j:=1 to n do//找从v0开始到目前为止,哪个结点作为下一个连接起点(*可优化) if (not visit[j]) and (min>d[j]) then//结点k要未被连接进去且最小
begin min:=d[j];k:=j;end;
visit[k]:=true;//连接进去
for j:=1 to n do//刷新数组d,通过k来更新到达未连接进去的节点最小值,
if (not visit[j]) and (d[j]>d[k]+a[k,j]) then d[j]:=a[k,j]+d[k];
end;
writeln(d[n]);//结点v0到结点n的最短路。
思考:在实现步骤时,效率较低需要O(n),使总复杂度达到O(n^2)。对此可以考虑用堆这种数据结构进行优化,使此步骤复杂度降为O(log(n))(总复杂度降为O(n log(n))。
实现:1. 将与源点相连的点加入堆(小根堆),并调整堆。
2. 选出堆顶元素u(即代价最小的元素),从堆中删除,并对堆进行调整。
3. 处理与u相邻(即下一个)未被访问过的,满足三角不等式的顶点
1):若该点在堆里,更新距离,并调整该元素在堆中的位置。
2):若该点不在堆里,加入堆,更新堆。
4. 若取到的u为终点,结束算法;否则重复步骤2、3。
**优化代码:(DIJKSTRA+HEAP)
program SSSP;{single source shortest path}
{假设一个图的最大节点数为1000,所有运算在integer范围内}
{程序目标:给定有向图的邻接表,求出节点1到节点n的最短路径长度}
const maxn=1000;{最大节点数}
var
n:integer;{节点个数}
list:array[1..maxn,1..maxn] of integer;{邻接矩阵,表示边的长度}
count:integer;{堆内元素个数计数器}
heap:array[1..maxn] of integer;{heap[i]表示堆内的第i的元素的节点编号} pos:array[1..maxn] of integer;{表示编号为i的元素在堆内的位置}
key:array[1..maxn] of integer;{表示节点1到节点i的最短距离}
exist:array[1..maxn] of boolean;{表示节点i是否存在于堆中}
i,j,now:integer;
procedure swap(var i,j:integer);{交换整数i和j}//省略
procedure heapify(p:integer);{向下调整堆的过程}
var best:integer;
begin
best:=p;//下面两个if是分别判断根和左、右孩子最短距离的大小
if (p*2<=count) and (key[heap[p*2]] if (p*2+1<=count) and (key[heap[p*2+1]] begin swap(pos[heap[p]],pos[heap[best]]);//互换节点heap[p]、heap[best]在堆的位置swap(heap[p],heap[best]);//互换堆中元素p、best heapify(best);//继续调整互换后的元素best end; end; procedure modify(id,new_key:integer); {判断new_key与key[id]大小,并修改key[id]大小} var p:integer; begin if (new_key begin//修改 key[id]:=new_key;//更新最短距离 p:=pos[id];//结点id在堆中的位置 while (p>1) and (key[heap[p]] begin swap(pos[heap[p]],pos[heap[p div 2]]); swap(heap[p],heap[p div 2]); p:=p div 2;//更上一层 end; end; end; procedure extract(抽出)(var id,dis:integer); {读取堆中最小元素的节点编号和节点1到该节点的距离} begin id:=heap[1];//堆顶 dis:=key[id]; dec(count);//出堆 if (count>0) then//堆里还有元素 begin