首页 > 其他分享 >Dijkstra(迪杰斯特拉)

Dijkstra(迪杰斯特拉)

时间:2024-05-14 13:54:54浏览次数:22  
标签:mini int graph rep 迪杰 ii Dijkstra 斯特拉 dis

Dijkstra(迪杰斯特拉)算法

简单版

须知

首先用几个数组表示需要的状态:

  • dis[] 表示距离从初始点到对应点的距离,初始点置为0,其他置为无穷
  • graph[][] 邻接矩阵,记录两点间连线的权重,可以记录无向图和有向图
  • check[] 判断当前点是否被记录

算法思路:

假定a为起点,每次选距离a最近的点然后更新。

image-20240428172502767

image-20240428172924153

先从a到b和c,发现到b的距离最小,锁定dis[b],

再从b到其他点,如图中第二次,发现从b到c为当前状态下最小的,所以记录

不断重复

代码

以https://www.luogu.com.cn/problem/P1339为例,AC代码如下

#define rep(i,j,k) for(i=(j);i<(k);i++)
const int N = 8000 + 10;
int ii, jj;

int n, m, s, t;
int u, v, w;
int graph[N][N];//邻接矩阵
int dis[N],check[N];//距离,状态
int main() {
    cin >> n >> m >> s >> t;
	//初始化,所有dis为无穷
    rep(ii, 0, n+1) {
        dis[ii] = INT_MAX;
        //graph全为0,表示无连接
        rep(jj, 0, n+1)
            graph[ii][jj] = 0;
    }
    
	//初始化,由于无向图,所以graph[u][v],graph[V][u]
    rep(ii, 0, m) {
        cin >> u >> v >> w;
        graph[u][v] = w;
        graph[v][u] = w;
    }
    //起点定为0
    dis[s] = 0;
    
    for (int i = 1; i <= n; i++) {
        //先遍历所有点,找出最小的
        int minn = INT_MAX, mini = 0;
        //该过程,即第i次寻找最小的dis,还要注意不能是已经选过的
        for (int j = 1; j <= n; j++) 
            if (!check[j] && dis[j] < minn) 
                minn = dis[j], mini = j;
		
        //将选中的置为1
        check[mini] = 1;

        //枚举邻边
        //从当前的最小位置向每个点连接,如果可以连接上,与原本的距离作对比
        for (int j = 1; j <= n; j++) {
            //从mini 到 i有连线,判断
            if (graph[mini][j] > 0) {
                dis[j] = min(dis[j], graph[mini][j] + minn);
            }
        }
        
    }
    cout << dis[t] << endl;
    return 0;
}

堆优化

学习原因

在找到最小距离时,枚举了很多并没有改变的点,额外提高了时间,所以用堆优化,把已经更改的点存入优先队列

之所以用优先队列,我们用距离d数组进行排序,最前面的就是我们要的那个mini。

int minn = INT_MAX, mini = 0;
for (int j = 1; j <= n; j++) 
    if (!check[j] && dis[j] < minn) 
        minn = dis[j], mini = j;

这时可以用一个优先队列来存储每次更新的点和路线长度,详情请参考:https://www.bilibili.com/video/BV1Ya411L7gb/?spm_id_from=333.999.0.0&vd_source=10b3ee1feea99fbdd76960a61a32f71e

具体实现

同样为上面简单版题目的ac代码

typedef pair<int, int> pii;
#define rep(i,j,k) for(i=(j);i<(k);i++)

const int N = 8000 + 10;
int ii, jj;

int n, m, s, t;
int u, v, w;
int graph[N][N];
int dis[N], check[N];
priority_queue<pii>pq;

int main() {
    cin >> n >> m >> s >> t;
    rep(ii, 0, n + 1) {
        dis[ii] = INT_MAX;
        rep(jj, 0, n + 1)
            graph[ii][jj] = 0;
    }

    rep(ii, 0, m) {
        cin >> u >> v >> w;
        graph[u][v] = w;
        graph[v][u] = w;
    }
    dis[s] = 0;

    //先将起点push进pq中
    pq.push({ 0,s });

    while(q.size()){
        //找到最小的顶点
        int mini = q.top().second;
        q.pop();
		//每次取top,因为此时的top表示的是从起点到达u点的最短长度
        //那么只需要从最短长度开始遍历其他点,就可以极大地降低时间复杂度
        
        if (vis[mini])continue;
        vis[mini] = 1;

        rep(j, 1, n + 1) {
            if (g[mini][j] > 0) {
                if (d[j] > d[mini] + g[mini][j]) {
                    d[j] = d[mini] + g[mini][j];
                    q.push({ -d[j],j });
                }
            }
        }
    }
    cout << dis[t] << endl;
    return 0;
}

注意:pq默认为大跟堆,如果用小跟堆会麻烦一点,所以将路径长度取-1再存储。路径只起到标识作用,不对结果产生影响。

标签:mini,int,graph,rep,迪杰,ii,Dijkstra,斯特拉,dis
From: https://www.cnblogs.com/lulaalu/p/18191146

相关文章

  • Dijkstra
    非常经典的单源最短路算法。仅能用于正权图(边权可为\(0\))拥有朴素版\(O(n^2)\)和堆优化版\(O((n+m)\log{m})\)朴素版一般用邻接矩阵存图而优化版使用邻接表或者链式前向星,我常用链式前向星中心思想每次在没用过的点内找一个距离起点最近的点,用这个点对其他点进行松弛操......
  • 洛谷P1576最小花费(逆Dijkstra算法)
    背景:说实话,这题有点考建模思想,及对Dijkstra算法的理解思路:因为转账间有手续费,即有一定损失比例,故边权均小于1(比例来说),而边的路权值非和,而是积,故边权相当于负(因为每次乘会使dis[i]变小)而题目刚好求最大路,而边权又等价于全为负,不刚好是Dijkstra的逆运用吗?原理:等......
  • 力扣周赛394之别样DP + 别样Dijkstra
    别样DP题目链接https://leetcode.cn/problems/minimum-number-of-operations-to-satisfy-conditions/description/题目大意题目思路需要考虑m列每一列填什么的情况,因为最终每一列都是一样的考虑暴力,每一列都可以变成0-9有\(10^m\)次种情况,这必然是不可行的我们从前往......
  • Dijkstra算法
    单源最短路算法,不能处理负环,朴素版时间复杂度\(O(n^2)\),堆优化版时间复杂度\(O(nlogn)\)。Dijkstra算法的流程是:将所有的节点分为A、B的两个集合,一开始A集合中只有起点,其他的节点在B集合。定义B中的节点与A的距离:若邻接A中的结点,则距离为边权;反之距离无穷大。1.找到与A距离最小......
  • 最短路算法(Dijkstra + SPFA + Floyd)
    最短路算法(Dijkstra+SPFA+Floyd)Dijkstra算法1.算法基本介绍Dijkstra算法通常是求解单源最短路中最快的算法,但它无法处理存在负权边的情况(原因在正确性证明中)。Dijkstra本质上是一种贪心算法,通过不断调整每个点的“当前距离”最终得到最优结果,其实后面要讲到的几种算法也大......
  • 【科研相关知识】Dijkstra算法
    Dijkstra算法相关背景知识历史来源exampleDijkstra算法相关背景知识Dijkstra算法是解决图论中的最短路径问题而最短路径问题是在图中找到两个节点之间的最短路径在导航中确定路线最短,在网络中路由器使用Dijkstra算法确定最短路径和转发端口。最短路径算法有Dijkstra算......
  • 【学习笔记】dijkstra
    一、dijkstra1.定义&作用很简单。一个单源最短路算法。2.思想&实现我觉得sm的图已经够了。二、堆优化dijkstra1.先来认识一下proirity_queue2.如何使用proirity_queue对dijkstra优化?每一步,我们都需要找到\(d\)值最小的节点(即\(......
  • FFmpeg 7.0 “Dijkstra” 发布
    FFmpeg7.0“Dijkstra”发布来源:OSCHINA编辑: 白开水不加糖2024-04-0710:11:00 2国产数据库圈,为啥那么多水货?”FFmpeg7.0“Dijkstra”现已发布。此版本以荷兰计算机科学家EdsgerW.Dijkstra的名字命名,一些值得注意的变化包括原生VVC解码器(目前处于......
  • DIjkstra进阶模板 路径记录 按权重(结点数最小等)记录
    structDIJ{usingi64=longlong;usingPII=pair<i64,i64>;vector<i64>dis,path,node;vector<vector<array<int,3>>>G;intn;DIJ(){}DIJ(intn):n(n){node.resize(n+1,1);......
  • Pintia 天梯地图 dijkstra进阶
    7-14天梯地图-SMU2024spring天梯赛3(补题)(pintia.cn)dijkstra进阶做法,包含路径记录,以及按权重统计路径条件等;不过最开始我一直将优先队列开的最大堆,但是一直过不了自己的例子,后来改成最小堆并且路径值改成负数存进去就对了,再后来我发现改成最大堆也可以,不过要把......