Dijkstra算法(一)
由于准备美赛,所以提前看一下相关书籍。
参考:数据建模算法与应用(第二版),https://blog.csdn.net/lbperfect123/article/details/84281300
简要
Dijkstra算法是典型最短路算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。
Dijkstra算法是很有代表性的最短路算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。
Dijkstra一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN, CLOSE表方式,Drew为了和下面要介绍的 A* 算法和 D* 算法表述一致,这里均采用OPEN,CLOSE表的方式。
其采用的是贪心法的算法策略
大概过程:
创建两个表,OPEN, CLOSE。
OPEN表保存所有已生成而未考察的节点,CLOSED表中记录已访问过的节点。
1. 访问路网中距离起始点最近且没有被检查过的点,把这个点放入OPEN组中等待检查。
2. 从OPEN表中找出距起始点最近的点,找出这个点的所有子节点,把这个点放到CLOSE表中。
3. 遍历考察这个点的子节点。求出这些子节点距起始点的距离值,放子节点到OPEN表中。
4. 重复第2和第3步,直到OPEN表为空,或找到目标点。
实例:
具体以书中例子为例:
eg:某公司在6个城市c1,c2,c3,c4,c5中有分公司,从c1到cj的直接航程票价记在下属邻接矩阵中(空格代表无效)。寻找一条c1到其他城市的最便宜的路线。
120 | 40 | |||
---|---|---|---|---|
120 | 40 | 20 | ||
30 | 20 | 30 | ||
40 | 20 | |||
20 | 30 |
Matlab:
clc,clear; a=zeros(5); a(1,3)=40;a(1,2)=120; a(2,5)=20;a(2,4)=40; a(3,4)=20;a(3,5)=30; a = a+a'; a(a==0)=inf pb(1:length(a))=0;pb(1)=1;index1=1;result=5;index2=ones(1,length(a));index3=index1; d(1:length(a))=inf;d(1)=0;minn=d(result); temp=1; while sum(pb)<length(a) tb = find(pb==0); d(tb)=min(d(tb),d(temp)+a(temp,tb)); if d(result)~=minn index3=[index3,temp]; end tmpb=find(d(tb)==min(d(tb))); temp=tb(tmpb(1)); pb(temp)=1; index1=[index1,temp];minn=d(result); temp2=find(d(index1)==d(temp)-a(temp,index1)); index2(temp)=index1(temp2(1)); end index3=[index3,result]; d,index1,index2,index3
变量解释:index1,index2,index3分别用来存放标号信息的,标号定点顺序,标号顶点索引,从始点到终点(result)的通路。
index2存放起始点到第i点的最短通路的第i顶点前一顶点的序号。
例如上述示例,c1到c5的通路为1->3->5。
当然,在记录路径信息的时候也可参照下面C++的方法把所有的最短通路的信息都显示出来(通过index2)。
C++:
#include<fstream> #define MaxNum 765432100 using namespace std; ifstream fin("Dijkstra.in.txt"); ofstream fout("Dijkstra.out.txt"); int Map[100][100]; bool is_arrived[100]; int Dist[100], From[100], Stack[100]; int p, q, k, Path, Source, Vertex, Temp, SetCard; int FindMin() { int p, Temp = 0, Minm = MaxNum; for (p = 1; p <= Vertex; p++) if ((Dist[p] < Minm) && (!is_arrived[p])) { Minm = Dist[p]; Temp = p; } return Temp; } int main() { memset(is_arrived, 0, sizeof(is_arrived)); fin >> Source >> Vertex; for (p = 1; p <= Vertex; p++) for (q = 1; q <= Vertex; q++) { fin >> Map[p][q]; if (Map[p][q] == 0) Map[p][q] = MaxNum; } for (p = 1; p <= Vertex; p++) { Dist[p] = Map[Source][p]; if (Dist[p] != MaxNum) From[p] = Source; else From[p] = p; } is_arrived[Source] = true; SetCard = 1; do { Temp = FindMin(); if (Temp != 0) { SetCard = SetCard + 1; is_arrived[Temp] = true; for (p = 1; p <= Vertex; p++) if ((Dist[p] > Dist[Temp] + Map[Temp][p]) && (!is_arrived[p])) { Dist[p] = Dist[Temp] + Map[Temp][p]; From[p] = Temp; } } else break; } while (SetCard != Vertex); for (p = 1; p <= Vertex; p++) if (p != Source) { fout << "========================\n"; fout << "Source:" << Source << "\nTarget:" << p << '\n'; if (Dist[p] == MaxNum) { fout << "Distance:" << "Infinity\n"; fout << "Path:No Way!"; } else { fout << "Distance:" << Dist[p] << '\n'; k = 1; Path = p; while (From[Path] != Path) { Stack[k] = Path; Path = From[Path]; k = k + 1; } fout << "Path:" << Source; for (q = k - 1; q >= 1; q--) fout << "-->" << Stack[q]; } fout << "\n========================\n\n"; } fin.close(); fout.close(); return 0; }
结果:
========================
Source:1
Target:2
Distance:90
Path:1-->3-->5-->2
========================
========================
Source:1
Target:3
Distance:40
Path:1-->3
========================
========================
Source:1
Target:4
Distance:60
Path:1-->3-->4
========================
========================
Source:1
Target:5
Distance:70
Path:1-->3-->5
========================
lingo解法请见Dijkstra 二。https://www.cnblogs.com/a-runner/p/14305894.html