- 龙之杰 的博客
Dijkstra求最短路
- @ 2025-1-11 21:24:20
题目
Background
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为非负值。 请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n号点,则输出 −1。
Input
第一行包含整数 n 和 m。 接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
Output
输出一个整数,表示 1号点到 n 号点的最短距离。 如果路径不存在,则输出 −1。
Limitation
1≤𝑛,𝑚≤1.5×10^5 1≤n,m≤1.5×10^5
思路
数据结构
从数据范围 可以看出输入的图是稠密图,用邻接矩阵肯定是不行的,但我们可以使用邻接表。
算法
直接暴力每一种方法一定会超时,所以我们可以使用Dijkstra来实现。
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,z,idx;
//h是邻接表数组:存储头节点
//c数组:存储边的目标节点
//ne数组:存储下一个节点
//d数组:存储边长
//dist数组:存储最短距离
int h[150001],c[300002],ne[300002],d[150001],dist[150001];
bool vis[150001];
//vis数组:标记
//向邻接表中添加边
void wsd(int x,int y,int z){
c[idx]=y;
d[idx]=z;
ne[idx]=h[x];
h[x]=idx++;
return;
}
int Dijkstra_plus(){
//优先队列q:存储节点及其与起点的距离
//first:距离,second:节点编号
priority_queue<pair<int,int>>q;
//初始化
memset(dist,0x3f,sizeof dist);
//起点到自身的距离为0
dist[1]=0;
//将起点及其距离加入优先队列
q.push({0,1});
while(!q.empty()){
//取当前距离起点最近的节点及其距离
pair<int,int>p=q.top();
q.pop();
//如果访问过,就跳过
if(vis[p.second]){
continue;
}
//标记该节点为已访问
vis[p.second]=1;
//遍历当前节点的所有邻接边
for(int i=h[p.second];i!=-1;i=ne[i]){
//如果通过当前节点到达邻接节点的距离更短(可以优化)
if(dist[c[i]]>dist[p.second]+d[i]){
//更新邻接节点到起点的最短距离
dist[c[i]]=dist[p.second]+d[i];
//将相连节点及其新的取负距离(取负是为了实现小根堆)加入
q.push({-dist[c[i]],c[i]});
}
}
}
//如果终点n的距离仍为极大值,说明无法到达,返回-1
if(dist[n]==0x3f3f3f3f){
return -1;
}
//返回从起点到终点n的最短距离
return dist[n];
}
int main(){
cin>>n>>m;
//初始化邻接表
memset(h,-1,sizeof h);
//读入每条边的信息,并添加到邻接表中
for(int i=1;i<=m;i++){
cin>>x>>y>>z;
wsd(x,y,z);
}
cout<<Dijkstra_plus();
return 0;
}