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行每行包含三 ...
随机推荐
- IntelliJ IDEA 搭建 Go 开发环境
本文介绍 Windows7 x64 基于 IntelliJ IDEA 搭建 Go 语言开发环境.主要是一些操作过程截图以及简单文字描述,如有不清楚的地方,欢迎指正.所有软件使用当前(2016.12. ...
- 【css】display:flex和display:box有什么区别
说法一: 注意:前者是flex 2012年的语法,也将是以后标准的语法,大部分浏览器已经实现了无前缀版本.后者是2009年的语法,已经过时,是需要加上对应前缀的.所以兼容性的代码,大致如下displa ...
- 用python 打印出爱心
其实,如果程序员真的很浪漫,普通人不懂,科技兴旺,也许你是惊呆了!!!!! 今天,泰泰又给你带来了一个“程序员技术(浪漫)表现”教程.飞鲸水龙头有希望它能在这个七月前夜帮到你.如果使用成功,记得给泰泰 ...
- JPA中的复杂查询
JPQL全称Java Persistence Query Language 基于首次在EJB2.0中引入的EJB查询语言(EJB QL),Java持久化查询语言(JPQL)是一种可移植的查询语言,旨在 ...
- 使用PHP 格式化时间
date 用法: date(格式,[时间]); 如果没有时间参数,则使用当前时间. 格式是一个字符串,其中以下字符有特殊意义: U 替换成从一个起始时间1970年1月1日以来的秒数 <?php ...
- 第二章、Django以及数据库的配置
目录 第二章.Django以及数据库的配置 一.小白必会三板斧 二.静态文件配置 三.form表单 action和method参数可以写的形式 四.request对象及方法 五.django连接数据库 ...
- 集合篇-----ArrayList与LinkedList之间的那些小事
各自特性: ArrayList : 是一由连续的内存块组成的数组,范围大小可变的,当不够时增加为原来1.5倍大小,数组. :调用trimToSize方法,使得存储区域的大小调整为当前元素数量所需要的 ...
- Java web中文乱码
1.设置工程的编码方式 window-preferences-general-workspace 改成uef-8 2.设置html的编码方式 <meta http-equiv="Con ...
- 通过LVM备份mysql数据库脚本
#!/bin/bash #******************************************************************** #encoding -*-utf8- ...
- appium自动化 - android
1. 获取driver appium通过生成driver来识别和操作app的UI元素.生成driver时,需要给出被测设备的相关信息.appium官方上的例子如下: https://github.co ...