c++课设报告《基于Dijkstra算法的最短路径问题求解》

课程设计任务书

目录

1 需求分析........................................... - 1 -

2 算法基本原理....................................... - 1 -

3 类设计............................................. - 2 -

4 详细设计........................................... - 3 -

4.1类的接口设计 (3)

4.2类的实现 (5)

4.3主函数设计 (10)

5 DOS界面程序运行结果及分析......................... - 11 -

5.1程序运行结果 (11)

5.2运行结果分析 (12)

6 基于MFC的图形界面程序开发........................ - 13 -

6.1基于MFC的图形界面程序设计 (13)

6.2程序测试 (15)

6.3MFC程序编写总结 (17)

7 参考文献........................................... - 17-

1 需求分析

Dijkstra 算法是由荷兰计算机科学家艾兹格·迪科斯彻发现的。算法解决的是有向图中最短路径问题。 举例来说,如果图中的顶点表示城市,而边上的权重表示著城市间开车行经的距离。 Dijkstra 算法可以用来找到两个城市之间的最短路径。

Dijkstra 算法的输入包含了一个有权重的有向图G ,以及G 中的一个来源顶点S 。 我们以V 表示G 中所有顶点的集合。图中的每一个边,都是两个顶点所形成的有序元素对。(u ,v )表示从顶点u 到v 有路径相连。 假设E 为所有边的集合,而边的权重则由权重函数w : E → [0, ∞]定义。 因此,w (u ,v )就是从顶点u 到顶点v 的非负花费值(cost)。 边的花费可以想像成两个顶点之间的距离。任两点间路径的花费值,就是该路径上所有边的花费值总和。 已知有V 中有顶点s 及t ,Dijkstra 算法可以找到s 到t 的最低花费路径(i.e. 最短路径)。 这个算法也可以在一个图中,找到从一个顶点s 到任何其他顶点的最短路径。

1.如果将交通网络化成带权图,假如用顶点表示城市,边表示公路段,则由这些顶点和边组成的图可表示沟通个城市的公路图,边的权用以表示两个城市之间的距离或者表示走过这段公路所需要的时间或通过这段路的难易程度等。作为司机和乘汽车的人,自然会关心如下两个问题:

(1)从甲地到乙地是否有公路?

(2)从甲地到乙地有几条公路,哪条公路最短或花费的代价最小?

这就是我们要讨论的最短路径问题。

2.迪杰斯特拉提出的一个求最短路径的算法。其基本思想是:按路径长度递增的顺序,逐个产生各最短路径。

3.首先引进辅助向量dist[],它的每一个分量dist[i]表示已经找到的且从源点0v 到每一个终点i v 的当前最短路径长度。它的初态为:如果从0v 到i v 有弧,则dist[i]为弧的权值;否则dist[i]为∞。其中,长度为dist[j]=min{dist[i]|i v ∈V}的路径是从0v 出发的长度最短的一条最短路径,此路径为(0v ,i v )。

2 算法基本原理

根据以上分析,可以得到如下描述的算法:

①假设用带权的邻接矩阵arce[i][j]来表示带权有向图,arce[i][j]表示弧上的权值。若不存在,则置arce[i][j]为∞(在计算机上可用允许的最大值代替)。S 为已找到的从0v 出发的最短路径的终点的集合,它的初始状态为空集。那么,从0v 出发到图上其余个顶点(终点)i v 可能达到的最短路径长度的初值为:

dist[i]=arce[Locate Vex(G,0v )][i]i v ∈S

②选择j v 得

dist[j]=min{dist[i]|i v ∈V-S}

j v 就是当前求得的一条从0v 出发的最短路径的终点。令S=S ∪{j}。

③修改从0v 出发到集合V-S 上任一顶点k v 可达的最短顶点长度。如果

dist[j]+arce[j][k]

则修改dist[k]为

dist[k]=dist[j]+arce[j][k]

④重复操作②、③共n-1次。由此求得从0v 到图上其余各顶点的最短路径是依路径长度递增的序列。

用Dijkstra 算法求有向图G 的0v 顶点到其余顶点v 的最短路径P[v]及其带权长度D[v]。

这个算法是通过为每个顶点v 保留目前为止所找到的从s 到v 的最短路径来工作的。初始时,源点s 的路径长度值被赋为0(d[s]=0), 同时把所有其他顶点的路径长度设为无穷大,即表示我们不知道任何通向这些顶点的路径(对于V 中所有顶点v 除s 外d[v]= ∞)。当算法结束时,d[v]中储存的便是从s 到v 的最短路径,或者是无穷大(如果路径不存在的话)。

Dijstra算法的基础操作是边的拓展:如果存在一条从u到v的边,那么从s到v的最短路径可以通过将边(u,v)添加到s到u的尾部来拓展。这条路径的长度是d[u]+w(u,v)。如果这个值比目前已知的d[v]的值要小,我们可以用新值来替代当前d[v]中的值。拓展边的操作一直执行到所有的d[v]都代表从s到v最短路径的花费。这个算法经过适当的组织因而当d[u]达到它最终的值的时候,每条边(u,v)都只被拓展一次。

算法维护两个顶点集S和Q。集合S保留了我们已知的所有d[v]的值已经是最短路径的值顶点,而集合Q则保留其他所有顶点。集合S初始状态为空,而后每一步都有一个顶点从Q移动到S。这个被选择的顶点是Q中拥有最小的d[u]值的顶点。当一个顶点u从Q中转移到了S中,算法对每条外接边(u,v)进行拓展。

Dijkstra(G,D,s){

//用Dijkstra算法求有向网G的源点s到各顶点的最短路径长度

//以下是初始化操作

S={s};D[s]=0; //设置初始的红点集及最短距离

for( all i∈ V-S )do //对蓝点集中每个顶点i

D[i]=G[s][i]; //设置i初始的估计距离为w //以下是扩充红点集

for(i=0;i

D[k]=min{D[i]:all i V-S}; //在当前蓝点集中选估计距离最小的顶点k

if(D[k]等于∞)

return; //蓝点集中所有蓝点的估计距离均为∞时,

//表示这些顶点的最短路径不存在。

S=S∪{k}; //将蓝点k涂红后扩充到红点集

for( all j∈V-S )do //调整剩余蓝点的估计距离

if(D[j]>D[k]+G[k][j])

//新红点k使原D[j]值变小时,用新路径的长度修改D[j],

//使j离s更近。

D[j]=D[k]+G[k][j];

}

}

3 类设计

从上面的算法分析可以看到,根据算法设计了类class SPFA ,public: int n;表示图里面的点数,public: int path[MAX][MAX];定义矩阵最多是1000个点,public: int dis[MAX];定义源点到其他点的距离,public: int src;定义源点,bool used[MAX]={false};定义点是否访问过了,初始化为未访问,初始化一下到各个点的距离,如果从k 点走到j 点的路很比原来的要短,那么更新,采用图的邻接矩阵或邻接表实现最短路径问题中图的存储,采用Dijkstra 算法求从某个源点到其余各顶点的最短路径。

第一步 先取()10W v =意即1v 到1v 的距离为0,而()j T v 是对()j T v 所赋的初

值。

第二步 利用()1W v 已知,根据()(){}min ,j i ij T v W v w +对()j T v 进行修正。

第三步 对所有修正后的()j T v 求出其最小者()k T v 。其对应的点k v 是1v 所能一步到达的点j v 中最近的一个,由于所有()0W u ≥。因此任何从其它点j v 中转而到达k v 的通路上的距离都大于1v 直接到k v 的距离()k T v ,因此()k T v 就是1v 到k v 的最短距离,所以在算法中令()()k k W v T v =并从s 中删去k v ,若k=n 则()()k n W v W v =就是1v 到n v 的最短路线,计算结束。否则令i k v v =回到第二步,继续运算,直到k=n 为止。

这样每一次迭代,得到1v 到一点k v 的最短距离,重复上述过程直到k n v v =。 Floyd 算法的基本原理和实现方法为:如果一个矩阵ij D d ??=??其中0ij d >表示i 与j 间的距离,若i 与j 间无路可通,则ij d 为无穷大。i 与j 间的最短距离存在经过i 与j 间的k 和不经过k 两种情况,所以可以令1,2,3,,k n =,n(n 为节点数)。检查ij d 与ik kj d d +的值,在此,ik d 与kj d 分别为目前所知的i 到k 与k 到j 的最短距离,因此,ik kj d d +就是i 到j 经过k 的最短距离。所以,若有ij ik kj d d d >+,就表示从i 出发经k 再到j 的距离要比原来的i 到j 距离短,自然把i 到j 的ij d 重写成ik kj d d +。

相关文档
最新文档