news 2026/9/7 10:18:18

【图论】最短路径-----Dijkstra篇

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【图论】最短路径-----Dijkstra篇

文章目录

【图论】最短路径

算法单源 / 多源支持负权边检测负权环时间复杂度适合场景
Dijkstra(堆优化)单源不支持O(mlogn)无负权,稀疏图,绝大多数题目首选
Bellman‑Ford单源支持O(nm)理论学习,实际做题很少手写
SPFA单源支持平均O(m),最坏O(nm)存在负权边、需要判负环;无负权不要用,容易被卡
Floyd‑Warshall多源(任意两点)支持O(n3)点数 n 很小,求全部点对最短路
  1. 单源:一个起点到其它所有点;多源:一次性得到任意两点之间最短距离
  2. 能检测负权环:可以判断图里有没有可以无限绕、距离越走越小的环
  3. Floyd 不能识别负环,图中有负环时结果失效。

最短路是图论中的经典问题即:给出一个有向图,一个起点,一个终点,问起点到终点的最短路径

Dijkstra算法

dijkstra 算法 同样是贪心的思路,不断寻找距离 源点最近的没有访问过的节点。

dijkstra三部曲

  1. 选源点到哪个节点近且该节点未被访问过
  2. 第二步,该最近节点被标记访问过
  3. 第三步,更新非访问节点到源点的距离(即更新minDist数组)

min_d:用来记录 每一个节点距离源点的最小距离

朴素版

过程:

  1. 初始化

    min_d数组初始化为longlong的最大值

    1. 选源点到哪个节点近且该节点未被访问过

    源点距离源点最近,距离为0,且未被访问。

    1. 该最近节点被标记访问过

    ​ 标记源点访问过

    1. 更新非访问节点到源点的距离(即更新min_d数组)

更新min_d数组,即:源点(节点1) 到 节点2 和 节点3的距离。


  1. 选源点到哪个节点近且该节点未被访问过

​ 未访问过的节点中,源点到节点2距离最近,选节点2

  1. 该最近节点被标记访问过

    节点2被标记访问过

  2. 更新非访问节点到源点的距离(即更新min_d数组)

更新min_d数组,即:源点(节点1)通过 已经计算过的节点(节点2) 可以链接到的节点 有 节点3,节点4和节点6


  1. 选源点到哪个节点近且该节点未被访问过

​ 未访问过的节点中,源点到节点3距离最近,选节点3

  1. 该最近节点被标记访问过

    节点3被标记访问过

  2. 更新非访问节点到源点的距离(即更新min_d数组)


  1. 选源点到哪个节点近且该节点未被访问过

​ 距离源点最近且没有被访问过的节点,有节点4 和 节点6,距离源点距离都是 5 (min_d[4] = 5,min_d[6] = 5) ,选哪个节点都可以。

  1. 该最近节点被标记访问过

​ 节点4被标记访问过

  1. 更新非访问节点到源点的距离(即更新min_d数组)


  1. 选源点到哪个节点近且该节点未被访问过

​ 距离源点最近且没有被访问过的节点,是节点6,距离源点距离是 5

  1. 该最近节点被标记访问过

​ 节点6 被标记访问过

  1. 更新非访问节点到源点的距离(即更新min_d数组)


  1. 选源点到哪个节点近且该节点未被访问过

​ 距离源点最近且没有被访问过的节点,是节点5,距离源点距离是 8

  1. 该最近节点被标记访问过

​ 节点5 被标记访问过

  1. 更新非访问节点到源点的距离(即更新min_d数组)


  1. 选源点到哪个节点近且该节点未被访问过

​ 距离源点最近且没有被访问过的节点,是节点7,距离源点距离是 12

  1. 该最近节点被标记访问过

​ 节点7被标记访问过

  1. 更新非访问节点到源点的距离(即更新min_d数组)

节点7加入,并不用更新数组

最后我们要求起点(节点1) 到终点 (节点7)的距离。

那么起到(节点1)到终点(节点7)的最短距离就是min_d[7] =12

最终路径

代码实现
#include<bits/stdc++.h>#definelllonglong#defineendl'\n'#defineIOSios::sync_with_stdio(0),cin.tie(0),cout.tie(0);#defineullunsignedlonglong#definefifirst#definesesecond#definePLLpair<ll,ll>#defineYEScout<<"YES"<<endl;#defineNOcout<<"NO"<<endl;usingnamespacestd;constll MAXN=5005;constll inf=0x3f3f3f3f;usingnamespacestd;ll n,m;ll l,r,v;intmain(){IOS cin>>n>>m;vector<vector<ll>>g(n+1,vector<ll>(n+1,LLONG_MAX));while(m--){cin>>l>>r>>v;g[l][r]=v;}vector<bool>vis(n+1,false);vector<ll>min_d(n+1,LLONG_MAX);ll start=1;ll end=n;min_d[1]=0;for(ll i=1;i<=n;i++){ll min_v=LLONG_MAX;ll cnt=1;for(ll j=1;j<=n;j++){if(!vis[j]&&min_d[j]<min_v){min_v=min_d[j];cnt=j;}}vis[cnt]=true;for(ll j=1;j<=n;j++){if(!vis[j]&&g[cnt][j]!=LLONG_MAX&&min_d[cnt]+g[cnt][j]<min_d[j]){min_d[j]=min_d[cnt]+g[cnt][j];}}}if(min_d[end]==LLONG_MAX){cout<<-1<<endl;}else{cout<<min_d[end]<<endl;}// cout<<fixed<<setprecision(x)<< ;return0;}

堆优化

(以边进行优化)

图的存储
vector<list<pair<int,int>>>g(n+1);

结构体

structp{ll point;ll v;};vector<list<p>>g;

先前是在通过遍历节点来遍历边,而现在我们用堆优化时,就是在直接遍历边,且是通过小顶堆来对边进行排序,直接选择距离源点最近的节点

实现代码
结构体形式

结构体形式的cmp函数会有点不好写,因为priority_queue不能自己cmp

// 这样写编译报错,不允许boolcmp(pair<ll,ll>a,pair<ll,ll>b){returna.se>b.se;}priority_queue<pair<ll,ll>,vector<pair<ll,ll>>,cmp>pq;
#include<bits/stdc++.h>#definelllonglong#defineendl'\n'#defineIOSios::sync_with_stdio(0),cin.tie(0),cout.tie(0);#defineullunsignedlonglong#definefifirst#definesesecond#definePLLpair<ll,ll>#defineYEScout<<"YES"<<endl;#defineNOcout<<"NO"<<endl;usingnamespacestd;constll MAXN=5005;constll inf=0x3f3f3f3f3f3f3f3f;structEdge{ll to,val;Edge(ll t,ll w):to(t),val(w){}};classmycomparison{public:booloperator()(constpair<ll,ll>&lhs,constpair<ll,ll>&rhs){returnlhs.se>rhs.se;}};usingnamespacestd;ll n,m;ll p1,p2,val;intmain(){IOS cin>>n>>m;vector<list<Edge>>grid(n+1);for(ll i=1;i<=m;i++){cin>>p1>>p2>>val;grid[p1].emplace_back(p2,val);}ll start=1;ll end=n;vector<ll>minDist(n+1,inf);vector<bool>visited(n+1,false);priority_queue<pair<ll,ll>,vector<pair<ll,ll>>,mycomparison>pq;pq.push({start,0});minDist[start]=0;while(!pq.empty()){pair<ll,ll>cur=pq.top();pq.pop();if(visited[cur.fi])continue;visited[cur.fi]=true;for(Edge edge:grid[cur.fi]){ll v=edge.to;ll w=edge.val;if(!visited[v]&&minDist[cur.fi]!=inf&&minDist[cur.fi]+w<minDist[v]){minDist[v]=minDist[cur.fi]+w;pq.push({v,minDist[v]});}}}if(minDist[end]==inf){cout<<-1<<endl;}else{cout<<minDist[end]<<endl;}return0;}
pair形式
#include<bits/stdc++.h>#definelllonglong#defineendl'\n'#defineIOSios::sync_with_stdio(0),cin.tie(0),cout.tie(0);#defineullunsignedlonglong#definefifirst#definesesecond#definePLLpair<ll,ll>#defineYEScout<<"YES"<<endl;#defineNOcout<<"NO"<<endl;usingnamespacestd;constll MAXN=5005;constll inf=0x3f3f3f3f3f3f3f3f;structEdge{ll to,val;Edge(ll t,ll w):to(t),val(w){}};ll n,m;ll l,r,v;intmain(){IOS cin>>n>>m;vector<list<Edge>>g(n+1);for(ll i=1;i<=m;i++){cin>>l>>r>>v;g[l].emplace_back(r,v);}ll start=1;ll end=n;vector<ll>min_d(n+1,inf);vector<bool>vis(n+1,false);priority_queue<PLL,vector<PLL>,greater<PLL>>q;q.push({0,start});min_d[start]=0;while(!q.empty()){PLL c=q.top();q.pop();ll dis=c.fi;ll u=c.se;if(vis[u])continue;vis[u]=true;for(Edge edge:g[u]){ll v=edge.to;ll w=edge.val;if(!vis[v]&&min_d[u]!=inf&&min_d[u]+w<min_d[v]){min_d[v]=min_d[u]+w;q.push({min_d[v],v});}}}if(min_d[end]==inf){cout<<-1<<endl;}else{cout<<min_d[end]<<endl;}return0;}

例题

参加科学大会

#include<bits/stdc++.h>#definelllonglong#defineendl'\n'#defineIOSios::sync_with_stdio(0),cin.tie(0),cout.tie(0);#defineullunsignedlonglong#definefifirst#definesesecond#definePLLpair<ll,ll>#defineYEScout<<"YES"<<endl;#defineNOcout<<"NO"<<endl;usingnamespacestd;constll MAXN=5005;constll inf=0x3f3f3f3f3f3f3f3f;structEdge{ll to,val;Edge(ll t,ll w):to(t),val(w){}};ll n,m;ll l,r,v;intmain(){IOS cin>>n>>m;vector<list<Edge>>g(n+1);for(ll i=1;i<=m;i++){cin>>l>>r>>v;g[l].emplace_back(r,v);}ll start=1;ll end=n;vector<ll>min_d(n+1,inf);vector<bool>vis(n+1,false);priority_queue<PLL,vector<PLL>,greater<PLL>>q;q.push({0,start});min_d[start]=0;while(!q.empty()){PLL c=q.top();q.pop();ll dis=c.fi;ll u=c.se;if(vis[u])continue;vis[u]=true;for(Edge edge:g[u]){ll v=edge.to;ll w=edge.val;if(!vis[v]&&min_d[u]!=inf&&min_d[u]+w<min_d[v]){min_d[v]=min_d[u]+w;q.push({min_d[v],v});}}}if(min_d[end]==inf){cout<<-1<<endl;}else{cout<<min_d[end]<<endl;}return0;}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 8:41:15

《异环》残虹G键隐身机制深度拆解与实战进阶技巧

各位玩家朋友大家好&#xff0c;今天想和大家认真聊一聊《异环》里残虹这个角色的一个核心机制——G键隐身。最近在“雾中朔望星回”版本里&#xff0c;娜娜莉老大回归&#xff0c;很多玩家又重新捡起了残虹&#xff0c;但我在游戏社区和私信里发现&#xff0c;不少人对残虹的隐…

作者头像 李华
网站建设 2026/9/3 20:16:10

Linux下explorer命令缺失的跨平台应用适配方案

如果你在 Linux 终端里敲下explorer&#xff0c;绝大多数发行版会回你一句冷冰冰的command not found。这件事单独看只是一个习惯差异&#xff0c;可一旦你的产品是跨平台桌面软件&#xff0c;它就会变成一个真实 bug&#xff1a;测试人员把包安装到国产 Linux 发行版上&#x…

作者头像 李华
网站建设 2026/9/5 10:40:11

Spark 本科毕业设计选题

选题分为 6 大方向&#xff1a;Spark 离线大数据分析、Spark Streaming/Structured Streaming 实时流处理、Spark 结合机器学习、Spark 与大数据生态集成、Spark 性能优化与调度研究、Spark 行业应用系统设计&#xff0c;难度覆盖普通本科、中等难度、偏创新型&#xff0c;可直…

作者头像 李华
网站建设 2026/9/4 17:47:54

2026铜陵工程建筑材料检测排名 TOP5 CMA 资质提供钢材检测、水泥检测、砂石检测 全覆盖联系方式推荐

铜陵建筑材料检测市场近年来机构数量激增&#xff0c;鳞次栉比的实验室招牌背后实则鱼龙混杂。建筑总包单位、建材生产厂家、市政工程项目、装修建设企业在选材验收时&#xff0c;稍有不慎便会遇上无资质机构出具的检测报告&#xff0c;最终无法用于工程报审与竣工验收备案。小…

作者头像 李华