Dijkstra算法

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表中记录已访问过的节点。

  1. 访问路网中里起始点最近且没有被检查过的点,把这个点放入OPEN组中等待检查。

  1. 从OPEN表中找出距起始点最近的点,找出这个点的所有子节点,把这个点放到CLOSE表中。

  1. 遍历考察这个点的子节点。求出这些子节点距起始点的距离值,放子节点到OPEN表中。

  1. 重复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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值