给定一个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思路:每次找到距离源点最近的还没有确定最近点的点,然后用此点试着去更新其他的点(松弛操作)
由于没有负权边,在未找到的点的集合中的dist[]最小的点,此时该点的的dist[]就是最近的dist[]了,因为它不可能再被优化了
因此改用最小堆的话,每次在堆顶的元素此时的dist[]就是它到源点的最短距离,然后用它来试着去松弛别的点,这就是dijkstra的思想
#include<iostream>
#include<string.h>
using namespace std;
int dist[510];
int st[510];
int g[510][510];
int n,m;
int dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1] = 0; // 刚开始的时候,源点也没有被访问过,即st[1] = 0
for (int i = 0; i < n; ++i){
int t = -1;
for (int j = 1; j <= n; ++j){
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
}
st[t] = true;
for (int j = 1; j <= n; ++j)
if (!st[j])
dist[j] = min(dist[t] + g[t][j],dist[j]);
}
if (dist[n] == 0x3f3f3f3f)
return -1;
return dist[n];
}
int main(){
int x,y,w;
cin>>n>>m;
memset(g,0x3f,sizeof g);
while(m--){
scanf("%d%d%d",&x,&y,&w);
g[x][y] = min(g[x][y],w);
}
cout<<dijkstra();
return 0;
}
// 堆优化版本 dijkstra
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int h[100010],e[100010],w[100010],ne[100010],dist[100010],st[100010],n,m,idx;
typedef pair<int,int> PII;
void add(int x,int y,int z){ // 表示边 x->y 边权为z
w[idx] = z;
e[idx] = y;
ne[idx] = h[x]; // 头插法
h[x] = idx++;
}
int dijstrak(){
dist[1] = 0;
priority_queue<PII,vector<PII>,greater<PII>> q;
q.push({dist[1],1}); // dist[i]:代表的是从原点到点i的最短距离,1代表的是该结点是第几个结点(从1开始)
while(q.size()){
PII t = q.top();
q.pop();
if (st[t.second]) continue;
st[t.second] = 1;
for (int i = h[t.second]; i != -1; i = ne[i]){
int j = e[i];
if (st[j]) continue;
if (dist[j] > t.first + w[i])
dist[j] = t.first + w[i];
q.push({dist[j],j});
}
}
if (dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof h);
memset(dist,0x3f,sizeof dist);
for (int i = 0; i < m; ++i){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
cout<< dijstrak();
return 0;
}