图——图的Dijkstra法最短路径实现

1,最短路径的概念:

1,从有向图中某一顶点(起始顶点)到达另一顶点(终止顶点)的路径中,其权值之和最小的路径;

2,问题的提法:

1,给定一个带权有向图 G 与起始顶点 v,求从 v 到 G 中其它顶点的最短路径(每条边上都存在有意义的权值);

2,Dijkstra 算法核心是通过已知最短路径寻找未知最短路径;

3,解决思路:

1,Dijkstra 提出按路径长度的递增次序,逐步产生最短路径;

1,首先求出长度最短的一条最短路径,再参照它求出长度次短的一条最短路径,依次类推,直到从起始顶点 v 到其它各顶点的最短路径全部求出为止;

2,核心是通过递归的方式将从起始顶点到其他各顶点的最短路径全部求出来;

4,准备工作:

1,辅助数组:Array<E> dist;

1,dist[i] 表示当前从起始顶点 v0 到顶点 vi 的路径长度;

2,初始设置:

1,若从起始顶点 v0 到顶点 vi 有边:dist[i] 为该边上的权值;

2,若从起始顶点 v0 到顶点 vi 无边:dist[i] 为无穷大;

5,Dijkstra 算法演示:

1,由非空顶点集和边集这两个图的基本定义可知,集合在图的算法分析中的重要性,而集合在数据结构中常表现为数组;

2,每次关注的是刚刚加入 S 集合的顶点到其他顶点的连接,通过刚刚求得的最短路径值来求出抵达其他顶点的可能的最短路径值,这就是核心;

6,Dijkstra 算法步骤:

7,Dijkstra 算法精髓:

1,S 集合内的顶点是已经找到最短路径的顶点;

2,v0 到 w 的最短路径只能通过 S 集内的顶点;

3,dist[w] 可能改变:

8,如何记录最短路径上的各个顶点?

1,定义辅助数组:

1,Array<int> path;

1,path[i] 表示当前路径上的顶点 i 的前驱顶点;

2,初始化:path = {-1};

3,修改:

9,Dijkstra 算法流程图:

10,Dijkstra 最短路径算法:

 1    /* 两个顶点之间最短路径,返回的数组表示两个最短路径上面的顶点 */
 2     SharedPointer< Array<int> > dijkstra(int i, int j, const E& LIMIT)  // O(n*n)
 3     {
 4         LinkQueue<int> ret;  // 保存最短路径上面的顶点
 5
 6         if( (0 <= i) && (i < vCount()) && (0 <= j) && (j < vCount()) )
 7         {
 8             DynamicArray<E> dist(vCount());  // 用于存储路径值
 9             DynamicArray<int> path(vCount());  // 用于存储当前结点的前驱结点
10             DynamicArray<bool> mark(vCount());  // 标记顶点是否进入 S 集合
11
12             /* 原材料初始化 */
13             for(int k=0; k<vCount(); k++)
14             {
15                 mark[k] = false;  // 顶点都没在 S 集合中
16                 path[k] = -1;  // 路径没有顶点前驱
17
18                 dist[k] = isAdjacent(i, k) ? (path[k]=i,getEdge(i, k)) : LIMIT;  // 如果初始结点和其他结点有连接,则设置为边上的权值,否则味无穷大;同时也要更新 path 数组,逗号表达式当前顶点 k 的前驱顶点是 i
20             }
21
22             mark[i] = true;  // 将起始顶点放入 S 集合中
23
24             /* 大循环 */
25             for(int k=0; k<vCount(); k++)
26             {
27                 E m = LIMIT;
28                 int u = -1;
29
30                 /* 遍历 dist 数组,从非S集合中找到到S 集合中顶点的最小路径值 */
31                 for(int w=0; w<vCount(); w++)
32                 {
33                     if( !mark[w] && (dist[w] < m) )  // 没有被标记的非 S 集中的点找最小值,更新小的值就是找最小路径值
34                     {
35                         m = dist[w];  // 找到了最小路径值
36                         u = w;  // 最短路径记录的顶点
37                     }
38                 }
39
40                 /* 判断是否有最小路径被找到,防止只有顶点没有边 */
41                 if( u == -1 )
42                 {
43                     break;  // 只有顶点没有边,找不到两点间最短路径,因为此时 dist 数组都是理论最大值,找不到最小值,直接跳出
44                 }
45
46                 mark[u] = true;  // 在非 S 集中找到了顶点 u 对应的路径值是最小值,放入 S 集合
47
48                 /* 算法核心:通过已知路径,推出 S 集合到非 S 集合顶点最短路径,由新加入的 u 来推动;这里的 w 是非 S 集合中的点,对其遍历;所有顶点都进入 S 集合中的时候,算法结束*/
49                 for(int w=0; w<vCount(); w++)
50                 {
51                     /* 以起始顶点 i 到 u 顶点的最短路径为基础,来计算通过已知最短路径所得到的到其它顶点路径是否最小,如果更小,则更新 dist 数组,这里的 w 是最小权值顶点 u 的邻接顶点,只要更小,就要更新 */
52                     if( !mark[w] && isAdjacent(u, w) && (dist[u] + getEdge(u, w) < dist[w]) )
53                     {
54                         dist[w] = dist[u] + getEdge(u, w);
55                         path[w] = u;  // 本次前驱顶点都是顶点 u 所代表的顶点
56                     }
57                 }
58             }
59
60             LinkStack<int> s;
61
62             s.push(j);  // 终止顶点 j 先放入栈中;
63
64             /* 将从起始顶点 i 到终值顶点 j 的点先放到栈中去;前驱结点的访问方式、值当做位置;值就是前面的顶点,所以直接把值压入进栈*/
65             for(int k=path[j]; k!=-1; k=path[k])
66             {
67                 s.push(k);
68             }
69
70             /* path 中保存的顶点顺序是逆序的,通过栈中转下,调整过来; */
71             while( s.size() > 0 )
72             {
73                 ret.add(s.top());
74
75                 s.pop();
76             }
77         }
78         else
79         {
80             THROW_EXCEPTION(InvalidParameterException, "Index <i, j> is invalid ...");
81         }
82
83         /* 最终最短路径经历顶点数至少有 2 个,否则 i 到 j 是不可达的,最多多少顶点是不知道的 */
84         if( ret.length() < 2 )
85         {
86             THROW_EXCEPTION(ArithmeticException, "There is no path from i to j ...");
87         }
88
89         return toArray(ret);  // 放到数组里面
90     }

11,Dijkstra 最短路径算法测试代码:

 1 #include <iostream>
 2 #include "MatrixGraph.h"
 3 #include "ListGraph.h"
 4
 5 using namespace std;
 6 using namespace DTLib;
 7
 8 template< typename V, typename E >
 9 Graph<V, E>& GraphEasy()
10 {
11    static MatrixGraph<4, V, E> g;
12
13     g.setEdge(0, 1, 1);
14     g.setEdge(0, 2, 3);
15     g.setEdge(1, 2, 1);
16     g.setEdge(1, 3, 4);
17    g.setEdge(2, 3, 1);
18
19     return g;
20 }
21
22 template< typename V, typename E >
23 Graph<V, E>& GraphComplex()
24 {
25    static ListGraph<V, E> g(5);
26
27     g.setEdge(0, 1, 10);
28     g.setEdge(0, 3, 30);
29     g.setEdge(0, 4, 100);
30     g.setEdge(1, 2, 50);
31     g.setEdge(2, 4, 10);
32     g.setEdge(3, 2, 20);
33    g.setEdge(3, 4, 60);
34
35     return g;
36 }
37
38 int main()
39 {
40     Graph<int, int>& g = GraphComplex<int, int>();
41    SharedPointer< Array<int> > p = g.dijkstra(0, 4, 65535);
42
43     for(int i=0; i<p->length(); i++)
44     {
45         cout << (*p)[i] << " ";
46    }
47
48    cout << endl;
49
50     return 0;
51 }

12,小结:

1,Dijkstra 最短路径算法是基于递推的思想完成的;

2,起始顶点到其他各顶点的最短路径通过动态推导得到;

3,未标记顶点的最短路径只能由已标记顶点计算得出;

4,算法的最终结果是起始顶点到其它各顶点的最短路径;

原文地址:https://www.cnblogs.com/dishengAndziyu/p/10926621.html

时间: 2024-11-10 13:35:34

图——图的Dijkstra法最短路径实现的相关文章

【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路.Seter保证不会有一个国家与自己之间有道路. Seter好不容易建好了所有道路,他现在在位于P号的首都.Seter想知道P号国家到任意一个国家最少需要经过几条道路.当然,Se

看数据结构写代码(35) 图的邻接矩阵表示法

杂谈:最近清明小长假,好好的放松了一下.节前 和 节后 都有点 松懈.不好,不好.贵在坚持.加油. 图的邻接矩阵表示法是用 两个数组 来表示 图的数据结构.一个是顶点数组,另一个是邻接矩阵数组.邻接矩阵 里存放着 顶点的关系. 用邻接矩阵表示图,在 看 顶点之间 是否有边,或者 求顶点的度等操作时比较简单.但空间浪费巨大,在插入,删除 顶点 和边 操作时 需要 移动大量数据,造成不便.所以在插入删除比较多,节点数比较多的时候 不宜 使用这种结构. 下面上代码: 源代码网盘地址:点击打开链接 //

Floyd-Warshall求图中任意两点的最短路径

原创 除了DFS和BFS求图中最短路径的方法,算法Floyd-Warshall也可以求图中任意两点的最短路径. 从图中任取两点A.B,A到B的最短路径无非只有两种情况: 1:A直接到B这条路径即是最短路径(前提是存在此路径): 2:A先通过其他点,再由其他点到B. 我们并不知道A是否需要通过其他点间接到达B,所以只能比较,用A到B的直接路径和A先通过其他点 再间接到达B的路径长度进行比较,然后更新为较小值. 上图中若要求顶点4到顶点3的最短路径,可以比较顶点4直接到3的路径和顶点4先到1,再到3

eoj1817 dijkstra单元最短路径 普通方法+二叉堆优化

求出有n(1 < n < 600)个结点有向图中,结点1到结点n的最短路径. Input 第一行有2个整数n和m(0 < m <= n*(n-1)/2),接下来m行每行有三个整数u,v,w结点u到v之间有一条权为w的边(w<1000000). Output 输出结点1到结点n之间的最短路径,如果1到n之间不存在路径,输出 -1. Sample Input 3 3 1 2 10 2 3 15 1 3 30 题目分析:dijkstra单元最短路径. 一.最短路径的最优子结构性质

算法-迪杰斯特拉算法(dijkstra)-最短路径

迪杰斯特拉算法(dijkstra)-最短路径 简介: 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. 算法思想: 设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中

数据结构--图--图的数组存储表示,深度优先搜索遍历和广度优先搜索遍历

图有四种存储结构:数组,邻接表,十字链表,邻接多重表.下面以数组为存储结构来实现图的深度优先搜索遍历和广度优先搜索遍历.其中广度优先搜索遍历中有用到STL中的queue,注意头文件的包含.具体代码如下: //图的数组(邻接矩阵)存储表示和深度优先遍历 const int MAX_VERTEX_NUM=20; //最大顶点数 typedef enum {DG,DN,UDG,UDN} GraphKind ;//(有向图,有向网,无向图,无向网) typedef int VRType; typedef

给他任何一套图图图u又哭了

夫人和翻译秃头一天又图图图5634564646464合格合格合格和非官方的活动符合东方给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭

15 图-图的遍历-基于邻接矩阵实现的BFS与DFS算法

算法分析和具体步骤解说直接写在代码注释上了 TvT 没时间了等下还要去洗衣服 就先不赘述了 有不明白的欢迎留言交流!(估计是没人看的了) 直接上代码: 1 #include<stdio.h> 2 #include<queue> 3 #include<iostream> 4 using namespace std; 5 typedef struct{ 6 int Vex[10];//顶点表 7 int Edge[10][10]; 8 int vexnum,arcnum;

UOJ #589. 图图的游戏

[题目描述]: 图图正在玩一个智力游戏:有一个n×n 的01 方格,图图要从中选出一个面积最大的矩形区域,要求这个矩形区域不能有超过k个1. 这么难的问题图图当然不会做了,他想让你帮帮他,你能解决这个问题吗? [输入描述]: 第一行包含2 个正整数n,k. 接下来n 行每行n 个整数,表示这个01方格. [输出描述]: 输出1 个整数,表示最大面积. [样例输入]: 5 4 1 0 1 0 1 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 0 0 1 0 1 [样例输出]: 12