原题链接 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.思路就是这样,往后就是大同小异了

链接:https://www.jianshu.com/p/ff6db00ad866

说了这么多,下面上代码:
#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 【模板】单源最短路径(标准版)题解的更多相关文章

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

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

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

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

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

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

  4. 洛谷 P4779 【模板】单源最短路径(标准版) 题解

    P4779 [模板]单源最短路径(标准版) 题目背景 2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路. 然后呢? 100 ...

  5. P4779 【模板】单源最短路径(标准版)

    P4779 [模板]单源最短路径(标准版) 求单源最短路, 输出距离 Solution \(nlogn\) 堆优化 \(Djs\) Code #include<iostream> #inc ...

  6. 洛谷 P4779【模板】单源最短路径(标准版)

    洛谷 P4779[模板]单源最短路径(标准版) 题目背景 2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路. 然后呢? 10 ...

  7. 洛谷 P3371 【模板】单源最短路径(弱化版) 题解

    P3371 [模板]单源最短路径(弱化版) 题目背景 本题测试数据为随机数据,在考试中可能会出现构造数据让SPFA不通过,如有需要请移步 P4779. 题目描述 如题,给出一个有向图,请输出从某一点出 ...

  8. 洛谷P4779 【模板】单源最短路径

    P4779 [模板]单源最短路径(标准版) 题目链接 https://www.luogu.org/problemnew/show/P4779 题目描述 给定一个 N个点,M条有向边的带非负权图,请你计 ...

  9. 最短路径 SPFA P3371 【模板】单源最短路径(弱化版)

    P3371 [模板]单源最短路径(弱化版) SPFA算法: SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环.SPFA 最坏情况下复 ...

  10. P3371 【模板】单源最短路径(弱化版)(Dijkstra算法)

    题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三 ...

随机推荐

  1. S02_CH05_UBOOT实验Enter a post title

    S02_CH05_UBOOT实验 5.1什么是固化 我们前几章的程序都是通过JTAG先下载bit流文件,再下载elf文件,之后点击Run As来运行的程序.JTAG的方法是通过TCL脚本来初始化PS, ...

  2. gulp做简单的js压缩

    安装工具 全局安装npm install --global gulp 项目的依赖安装npm install --save-dev gulp npm install --save-dev gulp-re ...

  3. ThreadLocal使用场景,原理

    ThreadLocal 1. 先说下 ThreadLocal不能解决多线程间共享数据,他是一个隔离多线程间共享数据的好帮手 2. ThreadLocal是本地线程共享数据 3. 他是以空间换时间 sy ...

  4. web储存的初级运用

    <html> <head> <meta charset="utf-8"> <title>web存储</title>< ...

  5. c# 将datatable中的数据保存到excel文件中

    using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Lin ...

  6. tomcat 的配置文件server.xml 几个端口的作用

    tomcat中server.xml配置文件中几个port的作用和区别 在tomcat的server.xml中有这么几个port,很多人虽然一直在使用tomcat,但是却不知道这几个port各有什么作用 ...

  7. Spring Boot Start 打包方式装B指南

    项目结构如下: test包:实际的代码 spring-boot-start-test包:start 配置包 代码详细配置如下 https://github.com/fqybzhangji/spring ...

  8. 英语是学习Java编程的基础吗

    就当前市场行情需求来看,Java人才需求依旧火爆,在如今互联网时代,手机移动端的软件开发是非常重要的,如今无论是大中小企业都是需要进行软件的开发的,又因为Java是开源的使用起来可以节约一大批的成本, ...

  9. openresty获取nginx中的变量

      在OpenResty中如何引用这些变量呢? 规则很简单, 如$remote_addr, 在OpenResty里面使用就是ngx.var.remote_adddr.  

  10. 正则表达式 re模块的使用

    一 正则表达式 首先, 我们在网页上进行行注册或者登陆的时候经常能看到一些格式上的错误提示. 比如:你在注册百度账号的时候  https://passport.baidu.com/v2/?reg&am ...