题目链接

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. NKOJ1828 Feed Ratios饲料调配

    题目 好题!高斯消元切了! (其实只是单纯地想吐槽这道出现在"高斯消元"专练里的题,暴搜能过,goudoubuxie"Gauss") 下面是暴搜: #pragm ...

  2. Linux C语言链表你学会了吗?

    链表是一种常见的基础数据结构,结构体指针在这里得到了充分的利用.链表可以动态的进行存储分配,也就是说,链表是一个功能极为强大的数组,他可以在节点中定义多种数据类型,还可以根据需要随意增添,删除,插入节 ...

  3. ACM 数据读写/对拍

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

  4. popStar机机对战数据生成器代码(C#)

    代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; ...

  5. 聊聊@Transactional 的失效场景,有哪些坑?

    先别急着回答,看完再说也不迟嘛.我们都知道在 Spring 项目中,我们可以直接使用注解 @Transactional 来标识一个事务方法.然而,你可能并不知道这个事务是不是按照你想的方式执行.下面我 ...

  6. java性能优化常用工具jmap、jstack

    jmap:java内存映像工具 jmap用于生成堆转储快照,比较常用的option包括-heap,-histo,-dump [root@localhost script]# jmap -h Usage ...

  7. 『学了就忘』Linux基础命令 — 26、帮助命令

    目录 1.man命令 (1)man命令的快捷键 (2)man命令的帮助级别(了解即可) (3)man命令的使用 2.info命令 3.help命令 4.--help选项 1.man命令 man是最常见 ...

  8. 7-7 后缀式求值 (25分)的python实现

    exp=input().split() ls=list() def Cal(a,b,i): if i=="+": return a+b elif i=="-": ...

  9. [linux]centos7.4上安装MySQL-8.0.11【完美安装】

    版本声明 centos7.4 MySQL-8.0.11 1.我用的阿里云的虚拟主机,刚从windows换到linux,需要装下常用工具 #安装下sz rz常用到上传下载的命令 yum install ...

  10. Integer.valueOf()和Integer.parseInt()区别

    他们返回类型的不同是最大的原因. static int parseInt(String s) 将字符串参数作为有符号的十进制整数进行分析. static Integer valueOf(int i) ...