题目链接

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;

谢谢支持!

【模板】单源最短路径(Dijkstra)/洛谷P4779的更多相关文章

  1. 单源最短路径Dijkstra算法,多源最短路径Floyd算法

    1.单源最短路径 (1)无权图的单源最短路径 /*无权单源最短路径*/ void UnWeighted(LGraph Graph, Vertex S) { std::queue<Vertex&g ...

  2. [数据结构与算法-15]单源最短路径(Dijkstra+SPFA)

    单源最短路径 问题描述 分别求出从起点到其他所有点的最短路径,这次主要介绍两种算法,Dijkstra和SPFA.若无负权优先Dijkstra算法,存在负权选择SPFA算法. Dijkstra算法 非负 ...

  3. 单源最短路径——dijkstra算法

    dijkstra算法与prim算法的区别   1.先说说prim算法的思想: 众所周知,prim算法是一个最小生成树算法,它运用的是贪心原理(在这里不再证明),设置两个点集合,一个集合为要求的生成树的 ...

  4. 单源最短路径 dijkstra算法实现

    本文记录一下dijkstra算法的实现,图用邻接矩阵表示,假设图为无向图.而且连通,有向图,不连通图的做法相似. 算法简述: 首先确定"单源"的源.假设是第0个顶点. 维护三个数组 ...

  5. matlab练习程序(单源最短路径Dijkstra)

    图的相关算法也算是自己的一个软肋了,当年没选修图论也是一大遗憾. 图像处理中,也有使用图论算法作为基础的相关算法,比如图割,这个算法就需要求最大流.最小割.所以熟悉一下图论算法对于图像处理还是很有帮助 ...

  6. 洛谷P3371单源最短路径Dijkstra堆优化版及优先队列杂谈

    其实堆优化版极其的简单,只要知道之前的Dijkstra怎么做,那么堆优化版就完全没有问题了. 在做之前,我们要先学会优先队列,来完成堆的任务,下面盘点了几种堆的表示方式. priority_queue ...

  7. 洛谷P3371单源最短路径Dijkstra版(链式前向星处理)

    首先讲解一下链式前向星是什么.简单的来说就是用一个数组(用结构体来表示多个量)来存一张图,每一条边的出结点的编号都指向这条边同一出结点的另一个编号(怎么这么的绕) 如下面的程序就是存链式前向星.(不用 ...

  8. 【洛谷 p3371】模板-单源最短路径(图论)

    题目:给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 解法:spfa算法. 1 #include<cstdio> 2 #include<cstdlib> 3 #in ...

  9. [模板]单源最短路径(Dijkstra)

    如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 主要还是再打一遍最短路,这种算法我用的不多... #include<bits/stdc++.h> using namesp ...

  10. luogu3371 【模板】单源最短路径 dijkstra堆优化

    #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> ...

随机推荐

  1. USART波特率 vs SPI速率--学习笔记

    本篇文章将与大家探讨USART波特率 vs SPI速率.这里提出一个问题,为什么USART的波特率是内核时钟的1/8或者1/16,而SPI最快的频率可以是内核时钟的1/2. 请大家带着这个问题来阅读本 ...

  2. web性能检测工具lighthouse

    About Automated auditing, performance metrics, and best practices for the web. Lighthouse 可以自动检查Web页 ...

  3. surrounded-regions leetcode C++

    Given a 2D board containing'X'and'O', capture all regions surrounded by'X'. A region is captured by ...

  4. ACM 数据读写/对拍

    freopen()函数在ACM中的使用 - cfzjxz的专栏 - 博客频道 - CSDN.NET 在做acm题目的过程中,我们需要在本地机器上调试.调试过程中,如果输入数据少还可以接受,但如果输入数 ...

  5. python的分支结构

    python分支结构 if结构 python的 if 选择分支结构的基础语法如下,需要注意的是判断条件后面是半角的分号,它的作用相当于Java中的小括号 if 判断条件 : 代码块 elif 判断条件 ...

  6. vue路由监听和参数监听

    1.路由携带数据跳转 routerAction(hideDisplays, data) { switch (hideDisplays) { case "pubAccountMenu" ...

  7. idea使用git更新代码 : update project(git merge、git rebase)

    idea使用git更新代码 : 选中想要更新的项目,右键点击 git => repository => pull 这样使用一次后idea会自动建立选中分支的远程跟踪分支,以后可直接点击下图 ...

  8. JavaScript数组方法大集合

    JavaScript数组方法集合 本文总结一下js数组处理用到的所有的方法.自己做个笔记. 数组方法 concat() 合并两个或多个数组 concat()能合并两个或者多个数组,不会更改当前数组,而 ...

  9. 南京大学OS笔记(1)-应用眼中的操作系统

    南京大学OS笔记(1)-应用眼中的操作系统 早就想刷一刷南大JYY老师的os课.之前稍微看过几节,果然讲的风趣幽默,而且现场写代码展示水平确实很高,这次准备认真刷一刷然后好好记一下笔记.当然lab就不 ...

  10. vuex基础(vuex基本结构与调用)

    import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const modulesA = { state:{//状态 count: ...