Dijkstra 算法(2)

Dijkstra 算法(2)

1.例题

题目描述

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为非负值。

请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1

输入格式

第一行包含整数 nm

接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z

输出格式

输出一个整数,表示 1 号点到 n 号点的最短距离。

如果路径不存在,则输出 -1

数据范围

1n,m1.5×105,
图中涉及边长均不小于 0,且不超过 10000
数据保证:如果最短路存在,则最短路的长度不超过 109

输入样例:

3 3
1 2 2
2 3 1
1 3 4

输出样例:

3

注:本题来源于AcWing题库第850题

2.思路

没学过 dijkstra 算法的请到这里去。

首先,我们先来观察一下题目,1n,m1.5×105,

很明显,dijkstra 算法 O(n2) 的时间复杂度是会TLE的。

这时我们就需要进行优化了。

在寻找一个未标记且最近的点(下面我们把这个点叫做 t 点)时,朴素版 dijkstra 是需要套两重循环来找的,

那我们要在众多数中找一个最小值,能不能用堆来优化呢?

堆排序的时间复杂度为 O(mlogn),也正好符合我们的要求。

所以,我们便可以在每次用 t 点来修改 j 点的最短路时,把 j 点加到堆里去,进行堆排序操作。

这就是优化!

3.代码

本人用的是优先队列,用手写太麻烦了,我相信没多少人会故意去把代码往难里写

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=150005;
int n,m;
int w[N],h[N],e[N],ne[N],idx;
int dist[N];
bool st[N];
struct node{
int first,second;//代表距离和编号
bool operator < (const node &x) const{//重载运算符
return first>x.first;
}
};
void add(int a,int b,int c){//用邻接表存储的加边操作
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
int dijkstra(){
memset(dist,0x3f,sizeof(dist));
dist[0]=1;
priority_queue<node> heap;
node a={0,1};//先用1号点初始一下距离
heap.push(a);
while(heap.size()){//判断堆不空也就是看点没有遍历完
node t=heap.top();
heap.pop();
int ver=t.second,distance=t.first;
if(st[ver]) continue;//如果已经遍历过了就证明是一个冗余备份,直接跳过
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i]){//遍历所有t的能到达的点
int j=e[i];//遍历到的这个点到t点的距离
if(dist[j]>distance+w[i]){
dist[j]=distance+w[i];
node p={dist[j],j};//如果老距离大于新距离就更换并入堆
heap.push(p);
}
}
}
if(dist[n]==0x3f3f3f3f) return 0x3f3f3f3f;
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=1;i<=m;i++){
int a,b,w;
cin>>a>>b>>w;
add(a,b,w);
}
if(dijkstra()==0x3f3f3f3f) cout<<"-1";
else cout<<dist[n];
return 0;
}

当然,如果不想写重载运算符也可以去补齐小根堆的两个参数。

完~

如果觉得还不错,就点个赞吧,您的支持就是我最大的动力。

posted @   Rainforests  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示