Dijkstra算法
文章内容参考自:Dijkstra算法图文详解 - 爱码帮™分享编程知识和开发经验 (ekotlin.com)
一、算法思想
算法思想的详细介绍我在哔哩哔哩进行了说明:迪杰斯特拉算法(Dijkstra算法)_哔哩哔哩_bilibili
Dijkstra算法算是 贪心思想实现的,首先把起点到所有点的距离存下来找个最短的,然后松弛一次再找出最短的,所谓的 松弛操作就是,遍历一遍看通过刚刚找到的距离最短的点作为中转站会不会更近,如果更近了就更新距离,这样把所有的点找遍之后就存下了起点到其他所有点的最短距离。
迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。
这样一个有权图,Dijkstra算法可以计算任意节点到其他节点的最短路径
二、算法思路
1.指定一个节点,例如我们要计算 ‘A’ 到其他节点的最短路径
2.引入两个集合(S、U),S集合包含已求出的最短路径的点(以及相应的最短长度),U集合包含未求出最短路径的点(以及A到该点的路径,注意 如上图所示,A->C由于没有直接相连初始时为∞)
3.初始化两个集合,S集合初始时 只有当前要计算的节点,A->A = 0,U集合初始时为 A->B = 4, A->C = ∞, A->D = 2, A->E = ∞
4.从U集合中找出路径最短的点,加入S集合,例如 A->D = 2
5.更新U集合路径,if ( ‘D 到 B,C,E 的距离’ + ‘AD 距离’ < ‘A 到 B,C,E 的距离’ ) 则更新U
6.循环执行 4、5 两步骤,直至遍历结束,得到A 到其他节点的最短路径
三、Dijkstra算法与路径规划
Dijkstra算法是很有代表性的最短路径规划算法。一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN, CLOSE表方式,路径规划采用OPEN,CLOSE表的方式。
大概过程:
创建两个表,OPEN, CLOSE。
OPEN表保存所有已生成而未考察的节点,CLOSED表中记录已访问过的节点。
访问路网中里起始点最近且没有被检查过的点,把这个点放入OPEN组中等待检查。
从OPEN表中找出距起始点最近的点,找出这个点的所有子节点,把这个点放到CLOSE表中。
遍历考察这个点的子节点。求出这些子节点距起始点的距离值,放子节点到OPEN表中。
重复2,3,步。直到OPEN表为空,或找到目标点。
测试数据 其中 数字 1000000 代表无穷大
6
1000000 1000000 10 100000 30 100
1000000 1000000 5 1000000 1000000 1000000
1000000 1000000 1000000 50 1000000 1000000
1000000 1000000 1000000 1000000 1000000 10
1000000 1000000 1000000 20 1000000 60
1000000 1000000 1000000 1000000 1000000 1000000
结果:
D[0] D[1] D[2] D[3] D[4] D[5]
0 1000000 10 50 30 60
AC代码
#include <stdio.h>
#define MAX 1000000
int arcs[10][10];//邻接矩阵
int D[10];//保存最短路径长度
int p[10][10];//路径
int final[10];//若final[i]= 1则说明 顶点vi已在集合S中
int n = 0;//顶点个数
int v0 = 0;//源点
int v,w;
void ShortestPath_DIJ()
{
for (v =0; v < n; v++) //循环 初始化
{
final[v] = 0; D[v] = arcs[v0][v];
for(w = 0; w < n; w++) p[v][w] = 0;//设空路径
if(D[v] < MAX) {p[v][v0] = 1; p[v][v] = 1;}
}
D[v0] =0; final[v0]=1; //初始化 v0顶点属于集合S
//开始主循环 每次求得v0到某个顶点v的最短路径 并加v到集合S中
for (inti = 1; i < n; i++)
{
intmin = MAX;
for(w = 0; w < n; w++)
{
//我认为的核心过程--选点
if (!final[w]) //如果w顶点在V-S中
{
//这个过程最终选出的点 应该是选出当前V-S中与S有关联边
//且权值最小的顶点 书上描述为 当前离V0最近的点
if (D[w] < min) {v = w; min = D[w];}
}
}
final[v] = 1; //选出该点后加入到合集S中
for(w = 0; w < n; w++)//更新当前最短路径和距离
{
/*在此循环中 v为当前刚选入集合S中的点
则以点V为中间点 考察 d0v+dvw 是否小于 D[w] 如果小于 则更新
比如加进点 3 则若要考察 D[5] 是否要更新 就 判断 d(v0-v3) + d(v3-v5) 的和是否小于D[5]
*/
if (!final[w] && (min+arcs[v][w]<D[w]))
{
D[w] = min + arcs[v][w];
// p[w] = p[v];
p[w][w] = 1; //p[w] = p[v] + [w]
}
}
}
}
int main()
{
freopen("./Dijkstra.txt", "r", stdin);
scanf("%d", &n);
for (inti = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
scanf("%d", &arcs[i][j]);
}
}
ShortestPath_DIJ();
for (inti = 0; i < n; i++) printf("D[%d] = %d\n",i,D[i]);
return 0;
}