Dijkstra 算法(2)

Dijkstra 算法(2)

1.例题

题目描述

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

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

输入格式

第一行包含整数 \(n\)\(m\)

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

输出格式

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

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

数据范围

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

输入样例:

3 3
1 2 2
2 3 1
1 3 4

输出样例:

3

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

2.思路

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

首先,我们先来观察一下题目,\(1≤n,m≤1.5×105\),

很明显,dijkstra 算法 \(O(n^2)\) 的时间复杂度是会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 @ 2022-08-10 23:00  Rainforests  阅读(58)  评论(0)    收藏  举报