【题目来源】
https://www.acwing.com/problem/content/851/
【题目描述】
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。
请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。
【输入格式】
第一行包含整数 n 和 m。
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
【输出格式】
输出一个整数,表示 1 号点到 n 号点的最短距离。
如果路径不存在,则输出 −1。
【数据范围】
1≤n≤500,
1≤m≤10^5,
图中涉及边长均不超过 10000。
【输入样例】
3 3
1 2 2
2 3 1
1 3 4
【输出样例】
3
【算法分析】
● Dijkstra 算法
Dijkstra 算法是一种用于解决有权图中单源最短路径问题的经典算法,由荷兰计算机科学家 Edsger W. Dijkstra 于 1956 年提出。以下是该算法的核心要点:
(1)适用范围:适用于带非负权重的有向图或无向图,无法处理含负权边的图。
(2)核心思想:采用贪心策略,逐步扩展离源点最近的未访问节点,更新邻接节点的最短距离。
● 链式前向星:https://blog.csdn.net/hnjzsyjyj/article/details/139369904
“链式前向星”就是“多单链表”,每条单链表基于“头插法”并用 e[]、ne[]、h[] 、val[] 等数组进行模拟创建。其中:
e[idx]:存储序号为 idx 的边的终点值
ne[idx]:存储序号为 idx 的边指向的边的序号(模拟链表指针)
h[a]:存储头结点 a 指向的边的序号
val[idx]:存储序号为 idx 的边的权值(可选)
● 本题基于链式前向星实现了有向图的 Dijkstra 算法。
本题的基于邻接矩阵的实现,详见:https://blog.csdn.net/hnjzsyjyj/article/details/147463593
● 代码解析
在这段 Dijkstra 算法的代码中,int t=-1 的作用是初始化一个临时变量 t,用于存储当前未访问节点中距离起点最近的节点编号。初始时,由于在 n 个节点的图中,除了起点之外,未访问节点只有 n-1 个,故循环只需进行 n-1 次。
【算法代码:有向图+链式前向星】
#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=5e2+5;
const int M=1e5+5;
int h[N],e[M],ne[M],val[M],idx;
int st[N],dis[N];
int n,m;
void add(int a,int b,int w) {
val[idx]=w,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int dijkstra() {
memset(dis,inf,sizeof dis);
dis[1]=0;
for(int i=1; i<n; i++) {
int t=-1;
for(int j=1; j<=n; j++) {
if(!st[j] && (t==-1 || dis[t]>dis[j])) t=j;
}
st[t]=true;
for(int i=h[t]; i!=-1; i=ne[i]) {
int j=e[i];
dis[j]=min(dis[j],dis[t]+val[i]);
}
}
if(dis[n]==inf) return -1;
return dis[n];
}
int main() {
memset(h,-1,sizeof(h));
cin>>n>>m;
while(m--) {
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
cout<<dijkstra()<<endl;
return 0;
}
/*
in:
3 3
1 2 2
2 3 1
1 3 4
out:
3
*/
【算法代码:有向图+邻接矩阵】
#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=505;
int dis[N],g[N][N];
bool st[N];
int n,m;
int dijkstra() {
memset(dis,inf,sizeof dis);
dis[1]=0;
for(int i=1; i<n; i++) {
int t=-1;
for(int j=1; j<=n; j++) {
if(!st[j] && (t==-1 || dis[t]>dis[j])) t=j;
}
st[t]=true;
for(int j=1; j<=n; j++) {
dis[j]=min(dis[j],dis[t]+g[t][j]);
}
}
if(dis[n]==inf) return -1;
return dis[n];
}
int main() {
cin>>n>>m;
memset(g,inf,sizeof g);
while(m--) {
int a,b,c;
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);
}
cout<<dijkstra()<<endl;
return 0;
}
/*
in:
3 3
1 2 2
2 3 1
1 3 4
out:
3
*/
【参考文献】
https://zhuanlan.zhihu.com/p/684656346
https://www.acwing.com/solution/content/38318/
https://blog.csdn.net/hnjzsyjyj/article/details/108951459