1 / 78

图算法(二)

图算法(二). 单源最短路经 Single-Source Shortest Path. 单源最短路径. 问题 : 带权有向图 G, 找出从给定 源顶点 s 到其它顶点 v 的权最小路径。 “ 最短路径 ” = 最小权 路径的权是路径上所有边的权之和。 例:道路图 : 从福州大学到东街口的最短路径是什么 ?. 权非负的单源最短路径算法 ( Dijkstra ). 贪心算法 基本思想 : 设置一个顶点集 S ,不断做贪心选择扩充这个集合。 一个顶点属于 S 当且仅当从源到该顶点最短路径长度已知。. 权非负的单源最短路径算法 ( Dijkstra ).

gay
Download Presentation

图算法(二)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 图算法(二) 单源最短路经 Single-Source Shortest Path

  2. 单源最短路径 • 问题: 带权有向图G, 找出从给定源顶点s到其它顶点v的权最小路径。 • “最短路径”= 最小权 • 路径的权是路径上所有边的权之和。 • 例:道路图 : 从福州大学到东街口的最短路径是什么?

  3. 权非负的单源最短路径算法(Dijkstra) • 贪心算法 • 基本思想: 设置一个顶点集S,不断做贪心选择扩充这个集合。 一个顶点属于S当且仅当从源到该顶点最短路径长度已知。

  4. 权非负的单源最短路径算法(Dijkstra) • 初始时,S仅包含源s, • 算法每次从V-S中取出具有最短特殊路径 长度的顶点u加入S中。 • 特殊路径: 从源到G中某一顶点u且中间只经过S中顶点的路称为从源到u的特殊路径。

  5. 权非负的单源最短路径算法(Dijkstra) Const P133 maxvalue=99999.0 maxlength=100; Type Arr1=array[1..maxlength] of integer; Arr2=array[1..maxlength,1..maxlength] of real; Arr3=array[1..maxlength] of real; Var prev:Arr1; c:Arr2; dist:Arr3; s:array[1..maxlength] of boolean n:integer; {邻接矩阵,c[i,j]为权} {dist[i]当前从源到顶点i的最短特殊路径长度(仅经过S中点) } {到该顶点最短路径长度 已知的顶点集S }

  6. B 2 10 A 4 3 D 5 1 C Ex: run the algorithm 权非负的单源最短路径算法(Dijkstr) Procedure shortpaths(n,v:integer); {单源最短路径问题的Digkstra算法} Var i,j,u:integer; temp,newdist:real; begin for i:=1 to n do begin dist[i]:=c[v,i]; s[i]:=false; if(dist[i]=maxvalue) then prev[i]:=0 else prev[i]:=v; end; Dist[v]:=0;s[v]:=true; {v到i的当前最短路径长度} 初始化 {源v加入到S}

  7. 从未加入S中的顶点 中选取当前特殊距 离最短的顶点加入 S 权非负的单源最短路径算法(Dijkstra) For i:=1 to n-1 do begin temp:=maxvalue; u:=v; for j:=1 to n do if ((not s[j]) and (dist[j]<temp)) then begin u:=j; temp:=dist[j]; end; s[u]:=true; Temp变量中保存的是什么值?

  8. 放松步 权非负的单源最短路径算法(Dijkstra) For j:=1 to n do if ((not s[j]) and (c[u,j]<maxvalue))then begin newdist:=dist[u]+c[u,j]; if (newdist<dist[j]) then begin dist[j]:=newdist; prev[j]:=u; end end end end; u是新加入S的顶点, 计算u的所有相邻顶点的特殊距离。若比原距离小,则用新距离代替,并让u做为最短路径上的点

  9. 2 2 10 1 4 3 4 5 1 3 Ex: run the algorithm If Dist[u]+c[u,j]<dist[j] then dist[j]=dist[u]+c[u,j] prev[j]=u S u dist[2] dist[3] dist[4] 1 - 10 5 maxvalue 1,3 3 9 5 6 1,3,4 4 8 5 6 1,3,4,2 2 8 5 6

  10. 权非负的单源最短路径算法(Dijkstra) • 基于邻接表的算法(当图边数远小于|V|2时采用)P136 Const maxint=2147483647 maxlength=1000 Type pointer=^adjnode;//邻接表 adjnode=record v:integer; //顶点标号 w:integer; //权 next:pointer; //指向下一邻接点指针 end; Arr1=array[1..maxlength] of longint; Arr2=array[1..maxlength] of integer; Arr3=array[1..maxlength] of pointer; Var dist: Arr1; //特殊距离 prev:Arr2; //i的前一节点 adj:Arr3; //邻接表 from,tto,n,e:integer; //源,目标,节点数,边数

  11. 负距离最大, 正距离则最小 权非负的单源最短路径算法(Dijkstra) Function DeleteMin:integer; //取当前负距离最大(正距离最小)的顶点 Var i,k:integer; temp:longint; begin k:=0; temp:=-maxint; for i:=1 to n do if (dist[i]<0) and (dist[i]>temp) then begin temp:=dist[i]; k:=i; end; DeleteMin:=k; End;

  12. 初始化当前距离为某一较小负整数,dist[i]<0表示i∈V-S初始化当前距离为某一较小负整数,dist[i]<0表示i∈V-S dist[i]>0表示i∈S, 省略数组S 节点i加入S后,dist[i]=- dist[i],变为正距离。 权非负的单源最短路径算法(Dijkstra) Function shortpath(from,tto:integer):boolean; Var i,k:integer; p:pointer; empty:boolean; begin for i:=1 to n do begin dist[i]:=-maxint; prev[i]:=0; end; k:=from; //源点 dist[k]:=0; //源点距离 empty:=false;

  13. 权非负的单源最短路径算法(Dijkstra) while (not empty) do {还有顶点未被加入S或未到目标顶点} Begin p:=adj[k]; while (p<>nil) do begin if (dist[p^.v]<0) and (dist[p^,v]<-(dsit[k]+P^.w)) then begin dist[p^.v]:=-(dist[k]+p^.w); prev[p^.v]:=k; end; p:=p^.next; End; K的第一个邻接点P 逐一考察K的所有邻接点,执行放松步 未加入S 放松步 K的下一个邻接点

  14. 权非负的单源最短路径算法(Dijkstra) k:=deletemin; //取当前负距离最大(正距离最小)点作为S中的点, If (k=0) or (k=tto) then empty:=true; //找不到当前特殊路径距离更小的顶点或到到目标节点 dist[k]:=-dist[k]; //k加入S End; Shortpath:=(k=tto); End;

  15. 2 2 10 1 4 3 4 5 1 3 Ex: run the algorithm 权非负的单源最短路径算法(Dijkstra) If Dist[u]+c[u,i]<dist[i] then dist[i]=dist[u]+c[u,i] prev[i]=u If –(Dist[u]+c[u,i])>dist[i] then dist[i]=-(dist[u]+c[u,i]) prev[i]=u k dist[2] dist[3] dist[4] DeleteMin 1 -10 -5 -maxint 3 -9 5 -6 4 -8 5 6 放松步 2 8 5 6 empty:=true;

  16. 有向无环图最短路径Directed acyclic graphs( DAG) Shortest Paths • 问题: 找出 DAG中的最短路径 • 思想: 利用拓扑排序(p138)。 若可构造DAG的顶点的拓扑排序,那么按该顺序可用O(|E|+|V|)时间计算最短路径。 排序后,第i+1个顶点最短路径上的点 一定是由前i个顶点中的点组成。(入度为0)

  17. 图:邻接表 1 3 nil 1 2 2 4 nil 2 4 2 3 3 4 3 nil 不能进行拓扑排序 存在环

  18. 拓扑排序算法 Function topsort:boolean; P140 var I,count:integer; indeg:Arr1; p:wpointer; q:queue; begin topsort:=true; count:=0; makenull(q); //清空队列q fillchar(indeg,sizeof(indeg),0);//数组indeg存储每个顶点入度

  19. //通过遍历邻接表,计算所有顶点的入度 For i:=1 to n do begin p:=wadj[i]; //顶点i的邻接表的第一个邻接点 while p<>nil do //依次为顶点i的所有邻接点入度加1 begin inc(indeg[p^.v]); p:=p^.next; end; End;

  20. //入度为0的顶点加入队列q For i:=1 to n do if indeg[i]=0 then enqueue(i,q); //入队 //队列q的队首顶点出队,与该顶点邻接的顶点的出度减1 While not empty(q) do begin ….P141 //入度为0的顶点数小于n时,存在环 If count<n then begin writeln(‘graph is cyclic’); topsort:=false; end; End;

  21. 有向无环图单源最短路径Directed acyclic graphs( DAG) Shortest Paths • Dag的单源最短路径问题具有最优子结构性质。 • 可对Dijkstra算法做进一步改进,可以在O(|E|+|V|)时间内求解单源最短路。

  22. 有向无环图单源最短路径Directed acyclic graphs( DAG) Shortest Paths Procedure reverse; P141 Var i:integer; Begin fillchar(top,sizeof(top),0); for i:=1 to n do top[ord[i]]:=i; End; 例:顶点 1 2 3 4 5 ord 2 3 1 5 4 top[ord[2]]=2 top 1 2 3 4 5top[2]=1 top[1]=3

  23. 不能排序?为什么不能??? 存在环 可以排序,计算DAG最短路径 有向无环图最短路径Directed acyclic graphs( DAG) Shortest Paths Function shortpath(s:integer):boolean; p142 var I,j,k:integer; p:wpointer; Begin if not topsort then begin shortpath:=false; exit; end; Reverse; Shortpath:=true; For i:=1 to n do begin dist[i]:=maxint; prev[i]:=0; end; dist[s]:=0;

  24. 按Top顺序考察所有排在顶点s之后的顶点 取与k相邻的所有顶点中当前特殊路径距离最短的点 放松步 有向无环图( DAG)最短路径Directed acyclic graphs Shortest Paths For i:=ord[s] to n do begin k:=top[i];{排在第i位顶点的顶点标号为k} p:=wadj[k]; {k的邻接点} while p<>nil do begin j:=p^.v; if dist[j]>dist[k]+p^.w then begin dist[j]:=dist[k]+p^.w; prev[j]:=k; end; p:=p^.next; end; end; End;

  25. 有负权边的有向图最短路径(Ford算法) Function shortpath(s:integer):boolean; P144 Var I,j,k:integer; p:wpointer; {图邻接表} Begin shortpath:=true; for i:=1 to n do begin dist[i]:=maxint; Count[i]:=0; prev[i]:=0; ub[i]:=false; {顶点i在队列qu中,则ub[i]=true} End; Makenull(qu);{清空队列qu} 变量初始化

  26. 有负权边的有向图最短路径(Ford算法) Dist[s]:=0 {源} Enqueue(s,qu); {源s入队} {当顶点的当前特殊路径长度改变时,该顶点入队qu. 对qu中顶点的邻接点执行放松步。} While (not empty(qu)) do begin k:=dequeue(qu); {k出队} ub[k]:=false; inc(count[k]); if count[k]>n then {存在负权环,无解} begin writeln(‘cycle of negative weight exists!’) shortpath:=false; exit; end; What will be the running time? A: O(VE)

  27. 有负权边的有向图最短路径(Ford算法) 逐一考察k的所有邻接点p,计算邻接点p经过顶点k的路径距离,若小于p原距离,则修改距离,p入队。 P:=wadj[k]; While (p<>nil)do begin j:=p^.v; if dist[j]:>dist[k]+p^.w then begin dist[j]:= dist[k]+p^.w ; prev[j]:=k; if not ub[j] then begin enqueue(j,qu); ub[j]:=true; end; end; P:=p^.next; end; end; end; 放松步 若j不在队列qu中,则入队

  28. Ford Algorithm 例 qu dist[2] dist[3] dist[4] dist[5] 1 Maxint maxint maxint maxint 2,3 -1 4 maxint maxint 3,4,5 -1 2 1 1 4 -1 2 -2 1 - -1 2 -2 1 2 1 0 3 4 nil 2 -1 -1 2 s 1 5 2 3 1 -3 4 3 4 5 Ex: work on board

  29. 所有顶点对间的最短路径问题(Floyd算法) 每次以一个顶点为源,重复执行Dijkstra n次? A: O(|V|3) Floyd算法:设v={1,2,…,n},邻接矩阵a a[i,j]= 0 i=j = c(i,j) (i,j)E = ∞ i≠j.(i,j)E 对邻接矩阵a做n次迭代。经过k次迭代后,a[i.j]的值是顶点i到j且不经过编号大于k的顶点的最短路径长度。 a(k)[i,j]=min(a(k-1)[i,j], a(k-1)[i,k]+a(k-1)[k,j]) 算法实现P146

  30. 例:

  31. 最短路径算法应用举例(一) 交通灯 • 问题描述 • D城道路连接不同路口,任意2个路口间至多有一条道路; • 任一道路不可连接同一路口; • 同一道路正反两方向通行时间相同; • 每一路口有一交通灯(蓝色和紫色交替变化),蓝色和紫 色信号都有特定持续时间 • 同一道路的两个路口的信号颜色相同时才可通行; • 当车辆到某路口时,该路口交通灯正在切换颜色,则当前 所显示的信号颜色是新切换的颜色 • 车辆不能通行时,允许其在路口等待。

  32. 最短路径算法应用举例(一) 交通灯 • 主要参数 • 2≤n≤300, n路口总数,1、2、…、n分别表示n个路口; • 1≤m≤14000,m是D城的道路数; • 1≤lij≤100,其中lij是从路口i到路口j的通行时间; • 1≤tic≤100,其中tic是路口i的交通灯显示颜色c的持续时间。C=B表示蓝色 C=P表示紫色; • 1≤ric≤tic,其中ric是路口i的交通灯初始颜色c的持续时间;

  33. 最短路径算法应用举例(一) 交通灯 • 输入数据 1 4 4 5 B 2 16 99 P 6 32 13 P 2 87 4 P 38 96 49 1 2 4 1 3 40 2 3 75 2 4 76 3 4 77 出发路口,到达路口

  34. 最短路径算法应用举例(一) 交通灯 • 输入数据 1 4 4 5 B 2 16 99 P 6 32 13 P 2 87 4 P 38 96 49 1 2 4 1 3 40 2 3 75 2 4 76 3 4 77 路口数n,道路数m

  35. 最短路径算法应用举例(一) 交通灯 • 输入数据 1 4 4 5 B 2 16 99 P 6 32 13 P 2 87 4 P 38 96 49 1 2 4 1 3 40 2 3 75 2 4 76 3 4 77 各路口的 初始颜色c,初始颜色持续时间ric ,蓝色持续时间tiB,紫色持续时间tiP

  36. 最短路径算法应用举例(一) 交通灯 • 输入数据 1 4 4 5 B 2 16 99 P 6 32 13 P 2 87 4 P 38 96 49 1 2 4 1 3 40 2 3 75 2 4 76 3 4 77 2 4 76 1 4 75 4 77 3 各道路的 道路连接的路口i,路口j,通行时间lij

  37. 最短路径算法应用举例(一) 交通灯 • 输出数据 127 1 2 4 2 4 75 1 4 最短通行时间 76 4 77 3 最短通行路径

  38. 最短路径算法应用举例(一) 交通灯 • 解题思路 • 带权无向图 • 利用交通灯控制,增加了路口等待时间。 权=通行时间+路口等待时间 2 4 75 可以用Dijkstra算法吗? 1 4 76 4 77 3 ???

  39. 最短路径算法应用举例(一) 交通灯 • 路口等待时间 权=通行时间+路口等待时间 (1)路口i与j颜色相同, 不必等待(wait=0)。 (2)颜色不同,等到颜色相同(最少等待时间)。 若i,j中有一个切换颜色(只有两种颜色)就相同,即i和j中最早切换颜色的时间是最少等待时间; 若i,j同时切换颜色,计算下一次最早切换时间; 若I,j连续三次同时切换颜色,则它们周期相同,i和j间道路永远不能通行。 2 4 75 1 4 76 4 77 3

  40. 最短路径算法应用举例(一) 交通灯 const maxint=2147483647; maxlength=300; Type pointer=^adjnode; adjnode=record v:integer; w:integer; next:pointer; end; lightype=record initcolor:integer; firstp:integer; initp:integer; secondp:integer; blue:integer; purple:integer; end; 图:邻接表 交通灯

  41. 最短路径算法应用举例(一) 交通灯 Arr1=array[1..maxlength] of longint; Arr2=array[1..maxlength] of integer; Arr3=array[1..maxlength] of pointer; Arr4=array[1..maxlength] of lighttype; Var dist:Arr1; prev:Arr2; adj:Arr3; light:Arr4; from,tto,n,e:integer; f:text; 当前特殊距离 最短路径的前一个顶点 顶点

  42. 最短路径算法应用举例(一) 交通灯 Function detcolor(i:integer;t:longint):integer; Begin detcolor:=light[i].initcolor;{初始颜色} if (t>=light[i].initp) and (((t-light[i].initp)mod(light[i].blue+light[i].purple))<light[i].secondp) then detcolor:=((light[i].initcolor+1)mod 2); End; 计算路口i在t时刻的交通灯颜色 初始颜色持续时间

  43. 最短路径算法应用举例(一) 交通灯 Function dettime(i:integer;color:integer;t:longint;var t1,t2,t3:integer); Begin if(t<light[i].initp)then begin t1:=light[i].initp-t; t2:=t1+light[i].secondp; t3:=t2+light[i].firstp; end else if (color=light[i].initcolor) then begin t1:=(light[i].secondp+light[i].firstp)-(t-light[i].initp)mod(light[i].secondp+light[i].firstp); t2:=t1+light[i].secondp; t3:=t2+light[i].firstp; end 计算路口it时刻后连续三次切换颜色的时间 时刻t小于初始颜色持续时间 时刻t大于初始颜色 持续时间,且颜色为初始颜色

  44. 最短路径算法应用举例(一) 交通灯 … else begin t1:=light[i].secondp-(t-light[i].initp)mod(light[i].secondp+light[i].firestp); t2:=t1+light[i].firstp; t3:=t2+light[i].secondp; end End; 时刻t大于初始颜色 持续时间,且颜色不是初始颜色

More Related