最短路问题(整理版)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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]]p then//若根有所变动,即跟比左右孩子都大(最短距离)

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

相关文档
最新文档