题目
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为非负值。
请你求出 11 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。
输入格式
第一行包含整数 n 和 m。
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
输出格式
输出一个整数,表示 1 号点到 n 号点的最短距离。
如果路径不存在,则输出 −1。
数据范围
1≤n,m≤150000
图中涉及边长均不小于 0,且不超过 10000。
数据保证:如果最短路存在,则最短路的长度不超过 1e9。
思路
使用小根堆来优化查询当前最短距离的点,使用当前没有遍历过的最小距离的点对其他的进行更新。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
const int N = 200010;
int n,m;//n个点,m条边
int h[N],e[N],ne[N],w[N],idx;// 邻接表四件套,w存放边的长度
int dist[N]; // 确定最小距离的点i距离点1的距离
bool st[N];// 表示这个点是否被遍历过
void add(int a,int b,int c)
{
e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;// 建立邻接表,并将边长存放在w中
}
int dijkstra()
{
memset(dist,0x3f,sizeof dist);
dist[1] = 0;// 点1已经确定,并且距离为0
priority_queue<PII,vector<PII>,greater<PII>> heap;// 小根堆,
heap.push({0,1});// 将点的距离存到first中,将点的编号存到second中。
while(heap.size())
{
auto t = heap.top();//取出这个小根堆中距离最小的点
heap.pop();// 将取出的点从小根堆中删除
int ver = t.second,distance = t.first;// 使用ver存点的编号,使用distance存放这个点到点1的最小距离
if(st[ver]) continue;// 如果这个点被遍历过,则直接进行下次循环
st[ver] = true;// 如果没有遍历过,就进行加下来的操作,并对这个点进行标记
for(int i = h[ver]; i != -1; i = ne[i])// 遍历这个点的邻接表
{
int j = e[i];// 跟这个点临接的某一个点的编号使用j存储。
if(dist[j] > distance + w[i])// 如果邻接点当前的距离大于,则更新这个点
{
dist[j] = distance + w[i];
heap.push({dist[j],j});
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main()
{
cin >> n >> m;
memset(h,-1,sizeof h);
while(m --)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
int ans = dijkstra();
cout << ans << endl;
return 0;
}