最短路径算法——Dijkstra 算法

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

最短路径算法——Dijkstra算法

一、最短路径问题

最短路问题是图论理论的一个经典问题。寻找最短路径就是在指定网络中两结点间找一条距离最小的路。最短路不仅仅指一般地理意义上的距离最短,还可以引申到其它的度量,如时间、费用、线路容量等。

最短路径算法的选择与实现是通道路线设计的基础,最短路径算法是计算机科学与地理信息科学等领域的研究热点,很多网络相关问题均可纳入最短路径问题的范畴之中。经典的图论与不断发展完善的计算机数据结构及算法的有效结合使得新的最短路径算法不断涌现。

在带权图(即网络)G=(V,E)中,若顶点v i,v j是图G的两个顶点,从顶点v i到v j 的路径长度定义为路径上各条边的权值之和。从顶点v i到v j可能有多条路径,其中路径长度最小的一条路径称为顶点v i到v j的最短路径。求最短路径具有很高的实用价值,在各类竞赛中经常遇到。一般有两类最短路径问题:一类是求从某个顶点(即源点)到其他顶点(即终点)的最短路径;另一类是求图中每一对顶点间的最短路径。

本讲主要讲述一种单源最短路径(Single source shortest path)算法——Dijkstra 算法,用于解决非负权有向图的单源最短路径问题。

二、Dijkstra算法

2.1 Dijkstra算法

Dijkstra算法是典型最短路算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率偏低。

Dijkstra算法是很有代表性的最短路算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。

2.2 Dijkstra算法思想

对于图G=(V,E),假设(u,v)是E中的边,c u,v是边的长度(即边权)。如果把顶点集合V划分为两个集合S和T:S中所包含的顶点,他们到u的距离已经确定;T中所包含的顶点,他们到u的距离尚未确定。同时,把源顶点u到T中的顶点x的距离d u,x,定义为从u出发,经过S中的顶点,但不经过T中其他顶点,而直接到达T中的顶点x的最短路径的长度。则Dijkstra算法的思想方法如下:

(1)开始时,S={u},T=V-{u}。对T中的所有顶点x,如果u到x存在边,则置d u,x=c u,x;否则,置d u,x=∞。

(2)对T中的所有顶点x,寻找d u,x最小的顶点t,即:

d u,t=min{d u,x|x∈T}

则d u,t就是顶点t到顶点u的最短距离。同时,顶点t也是集合T中所有顶点中距离u 最近的顶点。把顶点t从T中删去,把它并入S。

(3)对T中与t相邻接的所有顶点x,用下面的公式更新d u,x的值:

d u,x=min{d u,x,d u,t+c t,x}

(4)继续上述步骤,直到T为空集。

可参考swf文件:Dijkstra.swf帮助理解Dijkstra算法的算法思想。

2.3 Dijkstra算法举例说明

如下图,设A为源点,求A到其他各顶点(B、C、D、E、F)的最短路径。线上所标注为相邻线段之间的距离,即权值。

图一:Dijkstra无向图

算法执行步骤如下表:

2.4 Dijkstra算法实现

以邻接矩阵的方式存储有权无向图G,定义数据结构如下:

【关键过程】

【输出路径代码】

2.5 Dijkstra算法分析

Dijkstra算法的时间复杂度为O(n*n),空间复杂度为O(n)。

Dijkstra只适合解决非负权图的单源最短路径问题,对于有负权的图,Dijkstra算法将得到错误的结果。例如:下图从起点1到3的最短路径是-2(1->2->3),但是Dijkstra 在第2轮循环时找到最小的点3,并并入到S集合中,dist[3]=1,然而1却不是从起点1到3的最短路径,得到了错误的答案。

三、例题分析

1、comehome(comehome)

【问题描述】

现在是晚餐时间,而母牛们在外面分散的牧场中。农民约翰按响了电铃,所以她们开始向谷仓走去。你的工作是要指出哪只母牛会最先到达谷仓(在给出的测试数据中,总会有且只有一只速度最快的母牛)。在挤奶的时候(晚餐前),每只母牛都在她自己的牧场上,一些牧场上可能没有母牛。每个牧场由一条条道路和一个或多个牧场连接(可能包括自己)。有时,两个牧场(可能是字母相同的)之间会有超过一条道路相连。至少有一个牧场和谷仓之间有道路连接。因此,所有的母牛最后都能到达谷仓,并且母牛总是走最短的路径。当然,母牛能向着任意一方向前进,并且她们以相同的速度前进。牧场被标记为'a'..'z'和'A'..'Y',在用大写字母表示的牧场中有一只母牛,小写字母中则没有。谷仓的标记是'Z',注意没有母牛在谷仓中。注意'm'和'M'不是一个牧场。

【输入数据】

第 1 行:整数P(1<= P<=10000),表示连接牧场(谷仓)的道路的数目。

第 2..P+1行: 用空格分开的两个字母和一个整数:

被道路连接牧场的标记和道路的长度(1<=长度<=1000)。

【输出数据】

单独的一行包含二个项目:最先到达谷仓的母牛所在的牧场的标记,和这只母牛走过的路径的长度。

【样例输入】

5

A d 6

B d 3

C e 9

d Z 8

e Z 3

【样例输出】

B 11

【算法分析】

这道题题意很明确,求谷仓到其他牧场的最短路径,数据规模不大,直接用dijkstra

算法。但仔细阅读题目后,需要注意一些重要细节:

①同一个字母的小写字母和大写字母代表不同的牧场,即’a’和’A’不是同一牧场。

②两个点间的路径可能不止一条,保留较小值。

【参考代码】

program comehome;

const tn=26*2;// 本题中小写字母和大写字母代表不同牧场

var

f,pd:array[1..tn]of boolean;

d:array[1..tn]of longint;

map:array[1..tn,1..tn]of longint;

function deal(c:char):byte;

// 将字母转换为数字,'A'→1, 'a'→ 26+1 , 大写字母前26个,小写字母后26个

var

cn:integer;

begin

if c in['A'..'Z']then begin

cn:=ord(c)-ord('A')+1;

pd[cn]:=true;// 记录有牛的牧场

end

else cn:=ord(c)-ord('a')+1+26;

deal:=cn;

end;

procedure init;// 读入数据

var

n,i,s,t,dist:longint;

c:char;

begin

fillchar(pd,sizeof(pd),false);

assign(input,'comehome.in');

reset(input);

readln(n);

fillchar(d,sizeof(d),$3f);// d[i]表示到i点的最短路

// 初始化为极大值,不宜放maxlongint,否则会加法溢出(出现负数)

fillchar(f,sizeof(f),false);

for i:=1to n do begin

read(c);

s:=deal(c);

read(c);

read(c);

t:=deal(c);

相关文档
最新文档