基础图论算法最短路径Word下载.docx

上传人:b****6 文档编号:21215636 上传时间:2023-01-28 格式:DOCX 页数:44 大小:174.15KB
下载 相关 举报
基础图论算法最短路径Word下载.docx_第1页
第1页 / 共44页
基础图论算法最短路径Word下载.docx_第2页
第2页 / 共44页
基础图论算法最短路径Word下载.docx_第3页
第3页 / 共44页
基础图论算法最短路径Word下载.docx_第4页
第4页 / 共44页
基础图论算法最短路径Word下载.docx_第5页
第5页 / 共44页
点击查看更多>>
下载资源
资源描述

基础图论算法最短路径Word下载.docx

《基础图论算法最短路径Word下载.docx》由会员分享,可在线阅读,更多相关《基础图论算法最短路径Word下载.docx(44页珍藏版)》请在冰豆网上搜索。

基础图论算法最短路径Word下载.docx

  readln(n);

  fori:

=1tondo

  begin

  forj:

=1tondoread(a[i,j]);

  readln;

  end;

  fillchar(flag,sizeof(flag),false);

  flag[1]:

=true;

  minn:

=1;

  forx:

=2tondo

  begin

  min:

=32767;

  if(a[1,i]<

min)and(flag[i]=false)then

=a[1,i];

=i;

  flag[minn]:

  forj:

  if(j<

>

minn)and(a[1,minn]+a[minn,j]<

a[1,j])and(flag[j]=false)thena[1,j]:

=a[1,minn]+a[minn,j];

 end;

=1tondo  write(a[1,i],'

'

);

  end.

  4

  010030999

  10009910

  3099099

  99910990

  程序输出:

010030110

2.一般的dijkstra算法(邻接矩阵表示+最短的具体路径):

programzudlouj;

constn=6;

max=10000;

cost:

array[1..6,1..6]ofreal=((0,50,10,max,45,max),(max,0,15,max,10,max),(20,max,0,15,max,max),(max,20,max,0,35,max),(max,max,max,30,0,max),(max,max,max,3,max,0));

{连通关系,连通路径长度,不连通则赋值为max}

vardist:

array[1..n]ofreal;

{起点到当前点的最短路径}

path,p:

array[1..n]of1..n;

{path[i]:

记录以i为终点的到i点能取得最短路径的起点}

first,tail,u:

1..n;

{起点与终点}

s:

setof1..n;

{存储已走过的点}

i,j,y,m:

min:

real;

begin

read(first,tail);

fori:

=1tondodist[i]:

=max;

{一开始所有的点都赋值为∞表示没有走过}

dist[first]:

=0;

{起点赋值为0}

s:

=[first];

{起点已走过,存入s中}

u:

=first;

{u表示当前子路径的起点位置}

whileu<

taildo{当子路径的起点不是终点,即还没走到终点时}

begin

for 

j:

=1tondo

ifnot(jins)and(dist[u]+cost[u,j]<

dist[j])then{j表示子路径的终点,如果当前终点没有走过(不在s中)则看当前起点u到该点j的路径长度是否为到当前走到j的子路径中最短的,是则将到j的子路径的起点定位u(即path[j]:

=u),并且到j的最短路径dist[j]:

=dist[u]+cost[u,j]}

begindist[j]:

=dist[u]+cost[u,j];

path[j]:

=uend;

forj:

ifnot(jins)and(dist[j]<

min)thenbeginu:

=j;

min:

=dist[j];

end;

{找出当前子路径起点u所能到达的最短的j,并将j作为下一条子路径的起点u}

ifmin=max{如果min=max即当前点到四周所有的点都没有通路(死路一条了)}thenbeginwriteln('

Noanswer'

haltend;

=s+[u];

{将当前的子路径起点u放入s}

end;

{输出}

writeln('

mindist('

first,'

'

tail,'

)='

dist[tail]:

8:

2);

y:

=tail;

m:

while(y<

first) 

do

begininc(m);

p[m]:

=y;

y:

=path[y];

{p[1]:

1为终点,p[m]为起点(从后到前寻找回路径)}

write('

path:

'

first);

forj:

=mdownto1do 

write('

->

p[j]);

writeln;

end.

3.堆优化的dijkstra算法(dijkstra+邻接表+heap) 

programSSSP;

{singlesourceshortestpath}

{假设一个图的最大节点数为1000,所有运算在integer范围内}

{程序目标:

给定有向图的邻接表,求出节点1到节点n的最短路径长度}

constmaxn=1000;

{最大节点数}

var

n:

{节点个数}

deg:

array[1..maxn]ofinteger;

{每个节点的度数}

list:

array[1..maxn,1..maxn,1..2]ofinteger;

{邻接表,第一个元素表示边的终点,第二个元素表示边的长度}

count:

{堆内元素个数计数器}

heap:

{heap[i]表示堆内的第i的元素的节点编号}

pos:

{表示编号为i的元素在堆内的位置}

key:

{表示节点1到节点i的最短距离}

exist:

array[1..maxn]ofboolean;

{表示节点i是否存在于堆中}

i,j,now:

procedureswap(vari,j:

integer);

{交换整数i和j}

vartemp:

temp:

i:

=temp;

procedureheapify(p:

{调整堆的过程,向下调整}

varbest:

best:

=p;

if(p*2<

=count)and(key[heap[p*2]]<

key[heap[best]])thenbest:

=p*2;

if(p*2+1<

=count)and(key[heap[p*2+1]]<

=p*2+1;

ifbest<

pthen

swap(pos[heap[p]],pos[heap[best]]);

swap(heap[p],heap[best]);

heapify(best);

proceduremodify(id,new_key:

{判断new_key与key[id]大小,并修改key[id]大小,向上调整}

varp:

if(new_key<

key[id])then

key[id]:

=new_key;

p:

=pos[id];

while(p>

1)and(key[heap[p]]<

key[heap[pdiv2]])do

swap(pos[heap[p]],pos[heap[pdiv2]]);

swap(heap[p],heap[pdiv2]);

=pdiv2;

procedureextract(varid,dis:

{读取堆中最小元素的节点编号和节点1到该节点的距离}

id:

=heap[1];

dis:

=key[id];

dec(count);

if(count>

0)then

swap(pos[heap[1]],pos[heap[count+1]]);

swap(heap[1],heap[count+1]);

heapify

(1);

{读取数据}

readln(n);

read(deg[i]);

=1todeg[i]doread(list[i,j,1],list[i,j,2]);

{初始化}

exist[i]:

pos[i]:

heap[i]:

key[i]:

=maxint;

=n;

key[1]:

{dijkstra算法的主要操作}

while(count>

0)do

extract(i,now);

ifnow=maxintthenbreak;

=1todeg[i]do

ifexist[list[i,j,1]]thenmodify(list[i,j,1],now+list[i,j,2]);

ifkey[n]=maxintthenwriteln('

NotConnected!

){节点1和节点n不连通}

elsewriteln(key[n]);

{连通}

end.

SampleInput

6

3250310545

2315510

2120415

2220535

1450

143

SPFA算法

求单源最短路的SPFA算法的全称是:

ShortestPathFasterAlgorithm。

最短路径快速算法-SPFA算法是西南交通大学段凡丁于1994年发表的。

适用范围:

给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。

我们约定有向加权图G不存在负权回路,即最短路径一定存在。

当然,我们可以在执行该算法前做一次拓扑排序,以判断是否存在负权回路,但这不是我们讨论的重点。

算法思想:

我们用数组d记录每个结点的最短路径估计值,用邻接表来存储图G。

我们采取的方法是动态逼近法:

设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。

这样不断从队列中取出结点来进行松弛操作,直至队列空为止。

实现方法:

建立一个队列,初始时队列里只有起始点,再建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。

然后执行松弛操作,用队列里有的点作为起始点去刷新到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。

重复执行直到队列为空。

判断有无负环:

如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图);

我们还可以做一次拓扑排序,以判断是否存在负权回路(在没排完之前出现了没有入度为0的点,那么此图一定存在回路)。

单源最短路径中的松弛操作

对于图中的每个顶点v∈V,都设置一个属性d[v],描述从源点s到v的最短路径上权值的上界,称为最短路径估计。

pre[v]代表S到v的当前最短路径中v点之前的一个点的编号,我们用下面的过程来对最短路径估计和前趋进行初始化。

(O(V)时间)。

经过初始化以后,对所有v∈V,pre[v]=NULL,对v∈V-{s},有d[s]=0以及d[v]=∞。

实际松弛过程:

在松弛一条边(u,v)的过程中,要测试是否可以通过u节点,对迄今找到的v的最短路径进行改进;

如果可以改进的话,则更新d[v]和pre[v]。

一次松弛操作可以减小最短路径估计的值d[v],并更新v的前趋域pre[v](S到v的当前最短路径中v点之前的一个点的编号)。

下面的伪代码对边(u,v)进行一步松弛操作。

融入实际的单源最短路径的算法中。

RELAX(u,v,w)

if(d[v]>

d[u]+w(u,v))

{d[v]=d[u]+w(u,v);

pre[v]=u;

}

松弛是改变最短路径和前趋的唯一方式。

求右图a到g的最短路径

首先建立起始点a到其余各点的最短路径表格

a

b

c

d

e

f

g

d[i]

首先源点a入队,当队列非空时:

1、队首元素(a)出队,对以a为起始点的所有边的终点依次进行松弛操作(此处有b,c,d三个点),此时路径表格状态为:

24

8

15

在松弛时三个点的最短路径估值变小了,而这些点队列中都没有出现,这些点需要入队,此时,队列中新入队了三个结点b,c,d

队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e点),此时路径表格状态为:

30

在最短路径表中,e的最短路径估值也变小了,e在队列中不存在,因此e也要入队,此时队列中的元素为c,d,e

队首元素c点出队,对以c为起始点的所有边的终点依次进行松弛操作(此处有e,f两个点),此时路径表格状态为:

11

在最短路径表中,e,f的最短路径估值变小了,e在队列中存在,f不存在。

因此e不用入队了,f要入队,此时队列中的元素为d,e,f

队首元素d点出队,对以d为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:

19

在最短路径表中,g的最短路径估值变小了,g在队列中不存在,因此g要入队,此时队列中的元素为e,f,g

队首元素e点出队,对以e为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:

在最短路径表中,g的最短路径估值没有变小(松弛不成功),没有新结点入队,队列中元素为f,g

队首元素f点出队,对以f为起始点的所有边的终点依次进行松弛操作(此处有d,e,g三个点),此时路径表格状态为:

13

14

在最短路径表中,e,g的最短路径估值又变小,队列中无e点,e入队,队列中存在g这个点,g不用入队,此时队列中元素为g,e

队首元素g点出队,对以g为起始点的所有边的终点依次进行松弛操作(此处只有b点),此时路径表格状态为:

17

在最短路径表中,b的最短路径估值又变小,队列中无b点,b入队,此时队列中元素为e,b

在最短路径表中,g的最短路径估值没变化(松弛不成功),此时队列中元素为b

队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e这个点),此时路径表格状态为:

在最短路径表中,e的最短路径估值没变化(松弛不成功),此时队列为空了

最终a到g的最短路径为14

SPFA算法实现:

1.【邻接矩阵算法框架】

procedurespfa;

fillchar(q,sizeof(q),0);

h:

t:

//队列

fillchar(v,sizeof(v),false);

//v[i]判断i是否在队列中

fori:

=1tondod[i]:

//初始化最小值

inc(t);

q[t]:

v[1]:

//点1入队并做标记

d[1]:

//这里把1作为源点

whilenot(h=t)dobegin

x:

=q[(h+1)modn];

=(h+1)modn;

v[x]:

=false;

//出队

=1tondo//枚举x指向的点i

if(a[x,i]>

0)and(d[x]+a[x,i]<

d[i])then

begin

d[i]:

=d[x]+a[x,i];

//更新x指向点的最短路径长度

ifnot(v[i])thenbegin//如果i不在队列中,则将其放入队列,改进与之相关的点

=(t+1)modn;

v[i]:

 

2.【用邻接表表示的SPFA的算法】标准SPFA过程

(以求某个结点s到某个结点t的最短路为例,稍加修改即为单源最短路)

Pascal语言代码

programspfaprg;

const

maxp=10000;

{最大结点数}

var{变量定义}

p,c,s,t:

longint;

{p,结点数;

c,边数;

起点;

t:

终点}

a,b:

array[1..maxp,0..maxp]oflongint;

{a[x,y]存x,y之间边的权;

b[x,c]存与x相连的第c个边的另一个结点y}

d:

array[1..maxp]ofinteger;

{队列}

v:

array[1..maxp]ofboolean;

{是否入队的标记}

dist:

array[1..maxp]oflongint;

{到起点的最短路}

head,tail:

{队首/队尾指针}

procedureinit;

vari,x,y,z:

read(p,c);

fori:

=1tocdo

begin

readln(x,y,z);

{x,y:

一条边的两个结点;

z:

这条边的权值}

inc(b[x,0]);

b[x,b[x,0]]:

=y;

a[x,y]:

=z;

{b[x,0]:

以x为一个结点的边的条数}

inc(b[y,0]);

b[y,b[y,0]]:

=x;

a[y,x]:

end;

readln(s,t);

{读入起点与终点}

procedurespfa(s:

longint);

{SPFA}

vari,,j,now,sum:

fillchar(d,sizeof(d),0);

forj:

=1topdo

dist[j]:

=maxlongint;

dist[s]:

=0;

v[s]:

=true;

d[1]:

=s;

{队列的初始状态,s为起点}

head:

=1;

tail:

whilehead<

=taildo{队列不空}

now:

=d[head];

{取队首元素}

fori:

=1tob[now,0]do

ifdist[b[now,i]]>

dist[now]+a[now,b[now,i]]then

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 科学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1