【模板】单源最短路径(Dijkstra)/洛谷P4779

题目链接

https://www.luogu.com.cn/problem/P4779

题目大意

给定一个 \(n\) 个点 \(m\) 条边有向图,每个点有一个非负权值,求从 \(s\) 点出发,到每个点的最短距离。

数据保证能从 \(s\) 出发到任意点。

题目解析

朴素的 \(\mathrm{Dijkstra}\) 算法时间复杂度为 \(O(n^2)\)

使用优先队列 \(\mathrm{priority\_queue}\) 模拟小根堆(需要重定义)实现堆优化,每次查找最小值时间复杂度减小至 \(O(\log n)\)

时间复杂度 \(O(n \log n)\)

完整的参考代码中采用的是 \(\mathrm{pair<int,int>}\) 作为优先队列节点的比较容器,这种容器相当于包含两个参量的结构体,
比较顺序是:先比较第一个参量 \((\mathrm{first})\) ,再比较第二个参量 \((\mathrm{second})\)

当然也可以采用自定义结构体的方式,重载运算符后进行比较,下面也提供了三种较为常用的参考方法。

参考代码

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e5+5;
int n, m, s, dis[N];
priority_queue <pair<int, int>, vector <pair<int, int> >, greater<pair<int, int> > > Q;
vector <pair<int, int> > e[N];

inline int read()
{
    int X=0; bool flag=1; char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
    while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
    if(flag) return X;
    return ~(X-1);
}
void Dijkstra()
{
    dis[s] = 0;
    Q.push(make_pair(0, s));
    while (!Q.empty()){
        int a = Q.top().second, c = Q.top().first;
        Q.pop();
        if (c != dis[a]) continue;
        for (int i=0; i<e[a].size(); i++){
            int b = e[a][i].second;
            if (dis[b] > dis[a]+e[a][i].first){
                dis[b] = dis[a]+e[a][i].first;
                Q.push(make_pair(dis[b], b));
            }
        }
    }
}
int main() 
{
    int a, b, c;
    n=read(), m=read(), s=read();
    for (int i=0; i<m; ++i) {
        a=read(), b=read(), c=read();
        e[a].push_back(make_pair(c, b));
    }
    for (int i=1; i<=n; ++i) dis[i] = INF;
    Dijkstra();
    for (int i=1; i<=n; ++i) printf("%d ", dis[i]);
    putchar('\n');
    return 0;
}

自定义结构体的方法

方法1

由于优先队列 \(\mathrm{priority\_queue}\) 默认为大根堆,因此在结构体内部将“小于号”重载为“大于比较”即可,这是最简单的定义方法。

但是由于大小比较的不统一,往往容易引入其他由于混淆产生的错误或者带来检查上的困难。因此如这个结构体需要在代码内重复利用到的,则不推荐使用这种方法。

struct node{
    int c, a;
    bool operator < (const node &A) const {
        return c > A.c;//注意此处为大于号!
    }
};

priority_queue <node> Q;
//与priority_queue <node, vector<node>, less<node> > Q;等价
//其中std::less<Type>()为内置的小于比较类

方法2

在结构体内部将重载“大于号”,并在 \(\mathrm{priority\_queue}\) 中采用 \(std::greater<Type>()\) (大于比较类)来成为小根堆,这样在大小比较上是统一的。

struct node{
    int c, a;
    bool operator > (const node &A) const {
        return c > A.c;
    }
};

priority_queue <node, vector<node>, greater<node> > Q;

方法3

用自定义类来实现比较。

struct node{
    int c, a;
};
struct cmp{
    //操作符重载函数,必须是写()
    bool operator () (const node &A, const node &B){
        return A.c > B.c;//小根堆
    }
};
priority_queue <node, vector<node>, cmp> Q;

谢谢支持!

posted @ 2020-11-28 18:28  Chiron-zy  阅读(135)  评论(0编辑  收藏  举报