light5QAQ
文章11
标签10
分类6

文章分类

一言

文章归档

Dijkstra算法

Dijkstra算法

Dijkstra 算法是一种快速,便利地计算非负权图上单源最短路的算法。什么?你问我什么是图?好吧,让我们从头开始。图说白了就是许多连线的点,可以近似为城市和中间的路。图分为有向图和无向图,可以近似为单向路和双向路。权值就是通过这条路所需的代价,是一个数字。而单源最短路就是两个点之间的最短路径。


Dijkstra 算法的方法就是先将起点与其他点的举例设为inf,与自己的距离设为0. 再把点分为两种,已确定最短路长度的点集S,和未确定最短路长度的点集T. 一开始所有的点都属于T.
然后重复这些操作:

  1. 从T中,选取一个最短路长度最小的结点,移到S中.

  2. 对那些刚刚被加入S集合的结点的所有出边执行松弛操作.
    直到T为空,算法结束.
    至于什么是出边,就是可以出去的单行道,什么是松弛,就类似dp,重新计算距离.
    通常使用朴素做法或优先队列做法.


很简单对吧,那么你可以开始做题了。

P4779 【模板】单源最短路径(标准版)

题目描述

给定一个n个点,m条有向边的带非负权图,请你计算从s出发,到每个点的距离.
数据保证你能从s出发到任意点.

输入格式

第一行为三个正整数n,m,s. 第二行起m行,每行三个非负整数u[i],v[i],w[i],表示从 u[i]到v[i]有一条权值为w[i]的有向边.

输出格式

输出一行n个空格分隔的非负整数,表示s到每个点的距离。`

既然是模板题,那就直接上模板吧!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int inf=0x3f3f3f3f;
int vis[N]; //
int dis[N]; //存储点s与其他点的距离
int n,m,s;
struct node{
int v,w;
bool operator <(const node &x)const{
return x.w<w;
} //重定向 小于号把priority_queue变成小根堆
}; //存储最短路
vector<node> g[N]; //存距离
priority_queue<node> q; //优先队列默认大根堆
void dij(){
dis[s]=0; //自己为0
vis[s]=1; //
q.push(node{s,0}); //存入s本身
while(!q.empty()){
node t=q.top();
q.pop();
int now=t.v;
vis[now]=0;
for(int i=0;i<g[now].size();i++){
int v=g[now][i].v;
if(dis[v]>dis[now]+g[now][i].w){
dis[v]=dis[now]+g[now][i].w;
if(vis[v]==0){
q.push(node{v,dis[v]});
vis[v]=1;
}
}
}
}
}
int main(){
cin>>n>>m>>s;
for(int i=1;i<=n;i++){
dis[i]=inf; //存为inf
}
while(m--){
int u,v,w;
cin>>u>>v>>w;
g[u].push_back(node{v,w}); //存储权值
}
dij(); //Dijkstra
for(int i=1;i<=n;i++){
cout<<dis[i]<<" ";
}
return 0;
}

你看懂了吗?很好!那么我们再来做一道题练练手!

P1629 邮递员送信

题目描述

有一个邮递员要送东西,邮局在节点1. 他总共要送n−1样东西,其目的地分别是节点2到节点n. 由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有m条道路. 这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局. 求送完这n−1样东西并且最终回到邮局最少需要的时间.

输入格式

第一行包括两个整数,n和m,表示城市的节点数量和道路数量.
第二行到第(m+1)行,每行三个整数,u,v,w,表示从u到v有一条通过时间为w的道路.

输出格式

输出仅一行,包含一个整数,为最少需要的时间.

不难发现邮递员每次去要走最短路,回也要走最短路,那么只需要简单的正反跑Dijkstra就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,u,v,w;
long long ans;
struct node{
int x;
long long dis;
node(int X, long long DIS) : x(X),dis(DIS){} //这是什么意思呢
bool operator >(const node&o) const{return dis>o.dis;}
};
int inf=INT_MAX;
int ver[N],wei[N],nex[N],head[N],tot; //依次存储v w 下一个点 计数
priority_queue<node,vector<node>,greater<node> > q;
long long dis[N];
void addedge(int u, int v, int w){ //建边
ver[tot]=v,wei[tot]=w,nex[tot]=head[u],head[u]=tot++;
}
void dij(int s){
for(int i=1;i<=n<<1;++i) dis[i]=inf;
dis[s]=0;
q.push(node(s,0));
while(!q.empty()){
node cur=q.top();
q.pop();
if(dis[cur.x]<cur.dis) continue;
for(int i=head[cur.x];~i;i=nex[i]){
if(dis[ver[i]]>cur.dis+wei[i]) {
dis[ver[i]]=cur.dis+wei[i];
q.push(node(ver[i],dis[ver[i]]));
}
}
}
}
int main(){
memset(head,-1,sizeof(head));
cin>>n>>m;
for(int i=1;i<=m+1;i++){
cin>>u>>v>>w;
addedge(u,v,w);
addedge(v+n,u+n,w); //反向
}
dij(1);
for(int i=2;i<=n;++i) ans+=dis[i];
dij(1+n);
for(int i=2+n;i<=n<<1;++i) ans+=dis[i];
cout<<ans<<endl;
return 0;
}

本文作者:light5QAQ
本文链接:https://light5qaq.github.io/2025/08/23/Dijkstra%E7%AE%97%E6%B3%95/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可