P4779 【模板】单源最短路径(标准版)题解
原题链接 https://www.luogu.org/problemnew/show/P4779
若还未食用弱化版的同学请先做这个qwq https://www.luogu.org/problemnew/show/P3371
刚刚做完了弱化版的我,看到了这个标准版 双倍经验美滋滋qwq
把弱化版的SPFA模板打上去,改了下数据范围,提交!悲催的TLE了四个点!
很显然,这个题的数据是卡SPFA的,使得时间复杂度是SPFA最坏的复杂度!
那咋办呢?我们看到了
题目中已经说明了没有负权边,那么我们就可以用时间复杂度更为稳定的Dijkstra算法!
介绍一下下算法原理及实现:
假设我们有白点和蓝点,蓝点表示还未被松弛的点,白点表示已经松弛过的点,vis[i]=1代表是白点已经被松弛过了,vis[i]=0代表是蓝点还未被松弛过。我们的目标就是将所有的蓝点转化成白点;
1.从起点s开始,松弛它所有的出边,若某条边松弛成功且这条边的终点不在队列里,就让它入队,将起点标记为白点:vis[s]=1;
2.找到一个距离起点s最小的点(用优先队列实现),若该点是蓝点,那么松弛它所有的出边,若某条边松弛成功且这条边的终点不在队列里,就让它入队,将起点标记为白点:vis[i]=1;
重复第2个步骤,直到队列为空。
Dijkstra为什么是正确的?
当所有边长都是非负数的时候,全局最小值不可能再被其他节点更新.所以在第22步中找出的蓝点xx必然满足:dis[x]:dis[x]已经是起点到xx的最短路径..我们不断选择全局最小值进行标记和拓展,最终可以得到起点到每个节点的最短路径的长度。

算法图解
1.选定A节点并初始化,如上述步骤3所示

2.执行上述 4、5两步骤,找出U集合中路径最短的节点D 加入S集合,并根据条件 if ( 'D 到 B,C,E 的距离' + 'AD 距离' < 'A 到 B,C,E 的距离' ) 来更新U集合

3.这时候 A->B, A->C 都为3,没关系。其实这时候他俩都是最短距离,如果从算法逻辑来讲的话,会先取到B点。而这个时候 if 条件变成了 if ( 'B 到 C,E 的距离' + 'AB 距离' < 'A 到 C,E 的距离' ) ,如图所示这时候A->B距离 其实为 A->D->B

4.思路就是这样,往后就是大同小异了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int edge_sum; //暂时存边数
int n,m,s;
const int inf=1e9;
int read()
{
int a=;
char ch=getchar();
while(ch<''||ch>'') ch=getchar();
while(ch>=''&&ch<='')
{
a=a*+(ch-'');
ch=getchar();
}
return a;
}
int head[],vis[],dis[]; //head[i]表示以i结点为始点的最后一条出边,vis[i]表示i结点是否为白点,dis[i]表示i结点到起点s的最短距离
struct edge //定义一个结构体来存边的信息
{
int dis,pos,from,to,next;
bool operator < (const edge &x)const //重载小于号,根据dis来从小到大排序
{
return x.dis<dis;
}
}a[];
priority_queue<edge> q; //优先队列
void add(int from,int to,int dis) //链式前向星存图
{
edge_sum++;
a[edge_sum].next=head[from];
a[edge_sum].dis=dis;
a[edge_sum].from=from;
a[edge_sum].to=to;
head[from]=edge_sum;
}
int main()
{
n=read();m=read();s=read();
for(int i=;i<=m;i++)
{
int u=read();
int v=read();
int w=read();
add(u,v,w); //建图
}
for(int i=;i<=n;i++) dis[i]=inf,vis[i]=;//初始化
dis[s]=;
q.push((edge){,s}); //敲黑板,难点重点!!!我们优先队列定义的是edge类型的,所以我们放入一个edge类型的集合,集合中的第一个元素对应着结构体中的第一个成员,后之同理
//换句话说,这步操作就是将一个距离起点为0,编号为s的结点入队
while(!q.empty())
{
edge front=q.top(); //记录队列里的第一个元素,也就是dis最小的元素
q.pop(); //弹出队首元素
int wz=front.pos; //wz是该边的始点编号
if(vis[wz]==) continue; //如果该点已经在优先队列里了,那就没有松弛的必要了
vis[wz]=; //将始点标记为白点
for(int i=head[wz];i;i=a[i].next) //访问所有的出边
{
int zd=a[i].to; //这条边的终点
if(dis[zd]>dis[wz]+a[i].dis)
{
dis[zd]=dis[wz]+a[i].dis; //松弛
if(vis[zd]==) //若终点不在队列里的话
{
q.push((edge){dis[zd],zd}); //将松弛过的点都入队
}
}
}
}
for(int i=;i<=n;i++)
printf("%d ",dis[i]);
return ;
}
完结撒花qwq 双倍经验喽
P4779 【模板】单源最短路径(标准版)题解的更多相关文章
- [模板]单源最短路径(Dijkstra)
如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 主要还是再打一遍最短路,这种算法我用的不多... #include<bits/stdc++.h> using namesp ...
- 洛谷P3371单源最短路径Dijkstra版(链式前向星处理)
首先讲解一下链式前向星是什么.简单的来说就是用一个数组(用结构体来表示多个量)来存一张图,每一条边的出结点的编号都指向这条边同一出结点的另一个编号(怎么这么的绕) 如下面的程序就是存链式前向星.(不用 ...
- 【洛谷 p3371】模板-单源最短路径(图论)
题目:给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 解法:spfa算法. 1 #include<cstdio> 2 #include<cstdlib> 3 #in ...
- 洛谷 P4779 【模板】单源最短路径(标准版) 题解
P4779 [模板]单源最短路径(标准版) 题目背景 2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路. 然后呢? 100 ...
- P4779 【模板】单源最短路径(标准版)
P4779 [模板]单源最短路径(标准版) 求单源最短路, 输出距离 Solution \(nlogn\) 堆优化 \(Djs\) Code #include<iostream> #inc ...
- 洛谷 P4779【模板】单源最短路径(标准版)
洛谷 P4779[模板]单源最短路径(标准版) 题目背景 2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路. 然后呢? 10 ...
- 洛谷 P3371 【模板】单源最短路径(弱化版) 题解
P3371 [模板]单源最短路径(弱化版) 题目背景 本题测试数据为随机数据,在考试中可能会出现构造数据让SPFA不通过,如有需要请移步 P4779. 题目描述 如题,给出一个有向图,请输出从某一点出 ...
- 洛谷P4779 【模板】单源最短路径
P4779 [模板]单源最短路径(标准版) 题目链接 https://www.luogu.org/problemnew/show/P4779 题目描述 给定一个 N个点,M条有向边的带非负权图,请你计 ...
- 最短路径 SPFA P3371 【模板】单源最短路径(弱化版)
P3371 [模板]单源最短路径(弱化版) SPFA算法: SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环.SPFA 最坏情况下复 ...
- P3371 【模板】单源最短路径(弱化版)(Dijkstra算法)
题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三 ...
随机推荐
- 【数据结构】P1310 表达式的值
[题目链接] https://www.luogu.org/problem/P1310 题目描述 对于1 位二进制变量定义两种运算: 运算的优先级是: 先计算括号内的,再计算括号外的. “× ”运算优先 ...
- php 获取城市ip
/** * 获取ip城市信息 * CreateBy XueSong * @param string $ip * @return array|bool|mixed */ function getCity ...
- Java并发与多线程教程(2)
Java同步块 Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本文介绍以下内容: Java同步关键字(synchronzied) ...
- myEclipse10安装以及破解
这里需要下载一个破解补丁 https://pan.baidu.com/s/1ivE2yauZRDdDq8zBxpK06A 可以去网盘里下载, 下载后解压,会有如下文件 然后运行run.bat,会出现这 ...
- oracle数据库(实例)的导出与导入
Oracle数据导入导出常用两种方式: 1.是通过plsql-->tool-->export/import进行dmp文件的导入与导出: 2.使用命令imp/exp执行oracle数据导入与 ...
- Java在常见的spring面试问题TOP50
1. 一般问题 1.1. 不同版本的 Spring Framework 有哪些主要功能? Version Feature Spring 2.5 发布于 2007 年.这是第一个支持注解的版本. Spr ...
- Python入门之第三方模块安装
Python入门之第三方模块安装 平台:Win10 x64 + Anaconda3-5.3.0 (+Python3.7.0) Issue说明:pip install line_profiler-2.1 ...
- linux驱动程序与菜单关联
- oracle 初试 hint
最近在研究oracle的视图问题,本来想全转成 物化视图(materialized view)的,这样可以极大提升系统的响应时间,无奈工作量太大,所以就研究了SQL优化的问题. 我这个普通视图 有36 ...
- YOLO---Darknet下使用YOLO的常用命令
Darknet下使用YOLO的常用命令 整理了一下,随手记一下. 在终端里,直接运行时Yolo的Darknet的各项命令,/home/wp/darknet/cfg/coco.data文件,使用原件:= ...