1、实验9最短路径问题 最短路径问题及解法一、实验目的1. 了解求解最短路径的Dijkstra算法和Floyd算法的基本原理;2. 掌握Dijkstra算法和Floyd算法的基本步骤;3. 能应用相关的算法求解实际问题4掌握Dijkstra算法和Floyd算法的C程序设计技巧;2、实验内容1. 求解最短路径的Dijkstra算法及C程序实现2. 求解最短路径的Floyd算法及C程序实现1. 求解最短路径问题的Dijkstra算法问题1: 已知如图1 所示的单行线交通网, 它是一个有向图,每条弧旁的数字表示这条单行线的长度. 现在某人要从出发,通过这个交通网到去,求使下图中总路程最小的路径.图1引入
2、基本变量: ij: 各边的权数,d(v1,vj):v1到vj的路的总权数的最小值P标号:从v1到vj 的最短路径的权数已确定T标号:从v1到vj 的最短路径的权数的上界Si: 算法进行到第 i 步时,具P标号点的集合.(v)=m:从vs到v的最短路上,v的前一个点是vm, (v)=0,则v=vs.(v) =M:D中不含从vs到v的路;1.1 结合图表演示Dijkstra算法的基本步骤和基本原理我们用图表结全的方法讲述Dijkstra算法的基本步骤第一步因ij0,故 d(v1,v1)=0. v1加上P标号(图2中用划圈表示).图2表1 第一步被圈去的次序顶点从v1到该点的最短路的长度该节点的前一
3、个节点1v10起点v2v3v4v5v6v7v8v9第二步:从v1共发出3条弧,(v1,v2),(v1,v3),(v1,v4).若从v1出发沿(v1,v2)到达v2,权数为 d(v1,v1) + 12 = 6;若从v1出发沿(v1,v3)到达v3,权数为 d(v1,v1) + 13 = 3;若从v1出发沿(v1,v4)到达v4,权数为 d(v1,v1) + 14 = 1.mind(v1,v1) + 12, d(v1,v1) + 13,d(v1,v1) + 14 = min6, 3, 1= d(v1,v1) + 14 = 1故从v1出发到v4的路径的最小权必为1, 最短路是(v1,v4),d(v1
4、,v4) =1,给v4加上P标号(图3中加圈表示). 为什么?图3表2 第二步加P标号的次序顶点从v1到该点的最短路的长度该节点的前一个节点1v10起点v26v1v33v12v41v1v5v6v7v8v9第三步:加上红圈的点表示具有P标号, 现考查从v1及v4指向其余点的弧从v1出发,分别沿(v1,v2)、(v1,v3)到达v2,v3,权数分另别为6和3,从v4出发,沿(v4,v6)到达v6,权数为 d(v1,v4) +46 = 1 +10=11,mind(v1,v1) + 12,d(v1,v1) + 13,d(v1,v4) + 46 = min 6, 3, 11 = d(v1,v1) + 1
5、3 = 3故从v1到v3的最短路是(v1,v3),d(v1,v3)=3,v3加上P标号.图4表3 第3步加P标号的次序顶点从v1到该点的最短路的长度该节点的前一个节点1v10起点v26v13v33v12v41v1v5v611v4v7v8v9第四步:加上红圈的点表示具有P标号, 现考查从v1, v3和v4发出的弧. 从v1出发,沿(v1,v2)到达v2总权数为d(v1,v1) +126,从v3出发,沿(v3,v2)到达v2总权数为d(v1,v3) + 32=5,56, 因此到达v2的路径长度的上界应改为5, v2的前一个节点也应改为v3. 从v3出发,沿(v3,v4)到达v4,因v4已具有P标号
6、,不再参与计算. 从v4出发,沿(v4,v6)到达v6权数为 d(v1,v4) +46 = 1 +10=11,mind(v1,v1) + 12,d(v1,v3) + 32,d(v1,v4) + 46 = min 6, 5, 11 = d(v1,v1) + 13 = 3故从v1到v2的最短路是(v1,v3,v2),d(v1,v2)=5,v2加上P标号.图5表4 第4步加P标号的次序顶点从v1到该点的最短路的长度该节点的前一个节点1v10起点4v26, 5v1,v33v33v12v41v1v5v611v4v7v8v9按照同样的方法,重复这个过程即可得到从v1出发到v8的最短路,最终的表格如下:表5
7、 最终表格加P标号的次序顶点从v1到该点的最短路的长度该节点的前一个节点1v10起点4v26, 5v1,v33v33v12v41v15v56v27v611,10v4,v56v79v58v812v5v9从表中我们可以到得从从v1出发到v8的最短路的长度为12,具体路短为: v8v5v2v3v1 .1.2 Dijkstra算法的算法描述上文介绍的这个算法即为Dijkstra(迪杰斯特拉)算法,它是典型的单源最短路径算法,可用于计算一个节点到其他所有节点的最短路径. 主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. 对于给定的赋权有向图D=(V,A)(或无向图D=(V,E)),欲求从vs出
8、发到vt的最短路径(链), Dijkstra方法的具体步骤如下:Step 0: 令i=0,S0=vs, P(vs)=0, (vs)=0,对每一个vvs,令T(v)=+,(v)=M,令k = s.Step 1:如果vtSi,算法终止,对每个vSi,d(vs,v)=P(v);否则转下一步.Step 2: 考查每个使(vk,vj)A且vkSi的点vj.如果T(vj) P(vk) + wkj,则把T(vj)修改为P(vk) + wkj,把(vj)修改为k;否则转下一步.Step 3: 如果,则把的T标号变为P标号,令,若目标终点出现在Si+1中,终止,这时(I) 对每一个vSi,d(vs,v)=P(v
9、),(II) 对每一个,d(vs,v)=T(v).否则令i =i+1,转入Step 1.1.3 Dijkstra算法的C程序实现我们编写了Dijkstra算法的C语言程序, 并将程序应用于求解问题1,程序见附件,程序运行结果如下: /* Dijkstra 算法, 键盘输入起点和终点, 以图1.1的问题为例*/#include#define MIN(x,y) (x=y ? x : y)void main() double a1010, v103, t; int i, j, k, n=9, m, i0, m0; for (i=0; i=n; i+) for (j=0; j=n; j+) aij =
10、 -1; for (i=0; i=9; i+) for (j=0; j=2; j+) vij = -1; / 邻接矩阵 a12 = 6; a13 = 3; a14 = 1; a25 = 1; a32 = 2; a34 = 2; a46 = 10; a54 = 6; a56 = 4; a57 = 3; a58 = 6; a65 = 10; a67 = 2; a78 = 4; a98 = 3; a95 = 2; / i0: 起点下标, m0: 终点下标; puts(Please input the index of the staring point:); scanf(%d, &i0); puts
11、(Please input the index of terminal point: ); scanf(%d, &m0); i = i0; m = m0; n=9; / 点的总数 vi0 = 0; / 起点到起点的距离设为0 vi1 = 1; / 划圈的点置值1,其余为-1 vi2 = 0; / 前一个点的编号 while (1) for (j=1; j0) continue; t = aij; if (t 0.0) continue; t += vi0; if (vj0 0) vj0 = t; vj2 = i; else if( t vj0 ) vj0 = t; vj2 = i; t = 1
12、.0e20; for (j=1; j0 | vj0 0) continue; if (vj0 t ) t = vj0; k = j; vk1 = 1.0; i = k; if (k = m) break; for (j=1; j=n; j+) printf(%3d - %5.2f - %5.2f - %5.2fn, j, vj0, vj1, vj2); printf(The least chain is: %d, m); while (1) k = (int) (vm02); printf( - %d, k); m0 = k; if(k = i0) break; puts();练习:(1) 编
13、程实现用Dijkstra方法求下面的无向图中从v1到其它某个节点的距离的最小值,要求其它某节点待定,其序号由键盘输入。图6(2) 思考如何设计一个有类似于高德地图等手导航功能的程序。2. 求解最短路径的Floyd算法1.2 Floyd算法的基本思想Floyd-Warshall算法(Floyd-Warshall algorithm)是解决网络图中任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包. Floyd算法是一个经典的动态规划算法.从任意节点A到任意节点B的最短路径不外乎2种可能:1)直接从A到B,2)从A经过若干个节点X到B.我们假设
14、 dis(A,B)为节点A到节点B的最短路径的长度,对于每一个节点X,我们检查dis(A,X) +dis(X,B) dis(A, B)是否成立,如果成立,证明从A到X再到B的路径比从A直接到B的路径更短,我们便设置dis(A,B) = dis(A, X) + dis(X, B).这样一来,当我们遍历完所有节点X,Dis(A, B)中记录的便是A到B的最短路径的距离.2.2 Floyd算法的基本步骤Step 1 用数组disij来记录之间的最短距离;Step 2 初始化disij;若i=j则disij=0, 若之间有边连接则disij的值为该边的权值,否则disij的值为无穷大.Step 3 对
15、k从1到n循环,不断修正任意两点之间的最短距离. 若 disik+diskj disij 则令 disij= disik+diskj,否则disij的值不变. 2.3 Floyd算法的正确性的证明对于任意两点A,B:(1)当从A到B之间的最短路径,在中间没有经过节点或经过1个节点号为1的节点时,算法显然正确.(2)假设A到B经过的最大节点号不超过k-1时,算法得到的最短距离是正确的(3)当A到B的路径上经过的最大节点下标为 k 时,则从A到节点 之间的节点号均不大于k-1,从到B之间所有的节点号也不大于 k-1,由假设2得,A到的距离是中间节点号不超过的最短距离,到B的距离是中间节点号不超过k
16、-1的最短距离,所以A经到B为A,B之间经节点最大编号为 k 的路径中距离的最小值,由算法修正A,B的最短距离,即可得到A,B间节点编号不超过k的距离的最小值.(4)综上所述,算法是正确的2.4 Floyd算法的C程序实现我们编写了Floyd算法的C语言程序求解问题1, 程序见附件,程序运行结果如下:/ Floyd method, 以图1.1中的问题为例#include#define MIN(x,y) (x=y ? x : y)void main() double a1010, t; int i, j, k, n, m, i0, m0, path1010; n=9; for (i=0; i=n
17、; i+) for (j=0; j=n; j+) aij = 1.0e10; for (i=0; i=n; i+) for (j=0; j=9; j+) pathij = j; for (i=0; i=n; i+) aii = 0; a12 = 6; a13 = 3; a14 = 1; a25 = 1; a32 = 2; a34 = 2; a46 = 10; a54 = 6; a56 = 4; a57 = 3; a58 = 6; a65 = 10; a67 = 2; a78 = 4; a98 = 3; a95 = 2; for (k=1; k=n; k+) for(i=1; i=n; i+)
18、for(j=1; j aik + akj ) aij = aik + akj; pathij = pathik; puts(The matrix a:); for (i=1; i=n; i+) for (j=1; j=n; j+) printf(%5.1f , aij); puts(); puts(The matrix path:); for (i=1; i=n; i+) for (j=1; j , i0); i0 = pathi0m0; printf(%dn,m0);练习:(1) 编程实现用Floyd方法求下面的无向图中从v1到其它某个节点的距离的最小值,要求其它某节点待定,其序号由键盘输入。图6
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1