luogu P3371 & P4779 ---单源最短路径spfa & 最大堆优化Dijkstra

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

题目背景

本题测试数据为随机数据,在考试中可能会出现构造数据让SPFA不通过,如有需要请移步 P4779

题目描述

如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度。

输入输出格式

输入格式:

第一行包含三个整数N、M、S,分别表示点的个数、有向边的个数、出发点的编号。

接下来M行每行包含三个整数Fi、Gi、Wi,分别表示第i条有向边的出发点、目标点和长度。

输出格式:

一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度(若S=i则最短路径长度为0,若从点S无法到达点i,则最短路径长度为2147483647)

输入输出样例

输入样例#1:

4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4

输出样例#1:

0 2 4 3

说明

时空限制:1000ms,128M

数据规模:

对于20%的数据:N<=5,M<=15;

对于40%的数据:N<=100,M<=10000;

对于70%的数据:N<=1000,M<=100000;

对于100%的数据:N<=10000,M<=500000。保证数据随机。

对于真正 100% 的数据,请移步 P4779。请注意,该题与本题数据范围略有不同。

样例说明:

图片1到3和1到4的文字位置调换

解题思路:spfa算法是Bellman-Ford算法的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。spfa最坏情况下复杂度和朴素Bellman-Ford一样为O(|V||E|)。在非负边权图中为了避免出现最坏情况,通常使用效率更加稳定的Dijkstra算法,以及它的堆优化版本。数据较水,直接拿spfa板子水过。spfa思想:每次只需对上一次更新过的点的邻接点进行更新即可,因为上一次更新的点只对其未更新的邻接点有影响,所以无需像bellman-ford算法一样盲目遍历每条边。另外,出队的顶点要标记为false,即出队的那些点仍有可能对前面已更新过的点到源点的距离再进行更新,同时也要保证每个顶点至多在队列中出现1次,避免浪费时间去重复更新。

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn=1e5+5;
 5 const int inf=0x3f3f3f3f;
 6 queue<int> que;vector<int> v1[maxn],v2[maxn];int n,m,s,u,v,w,x,y,z,dis[maxn];bool vis[maxn];
 7 void spfa(int s){
 8     while(!que.empty())que.pop();
 9     que.push(s),vis[s]=true,dis[s]=0;
10     while(!que.empty()){
11         x=que.front();que.pop(),vis[x]=false;//出队则标记不在队列中
12         for(size_t j=0;j<v1[x].size();++j){
13             y=v1[x][j],z=v2[x][j];
14             if(dis[x]+z<dis[y]){
15                 dis[y]=dis[x]+z;
16                 if(!vis[y])que.push(y),vis[y]=true;//标记在队列中
17             }
18         }
19     }
20 }
21 int main(){
22     while(cin>>n>>m>>s){
23         for(int i=0;i<=n;++i)v1[i].clear(),v2[i].clear();
24         memset(vis,false,sizeof(vis));
25         while(m--){
26             cin>>u>>v>>w;
27             v1[u].push_back(v);//邻接点
28             v2[u].push_back(w);//对应边权
29         }
30         memset(dis,0x3f,sizeof(dis));
31         spfa(s);
32         for(int i=1;i<=n;++i)cout<<(dis[i]==inf?2147483647:dis[i])<<(i==n?‘\n‘:‘ ‘);
33     }
34     return 0;
35 }

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

题目背景

2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路。

然后呢?

100→60;

Ag→Cu;

最终,他因此没能与理想的大学达成契约。

小 F 衷心祝愿大家不再重蹈覆辙。

题目描述

给定一个 NN 个点,MM 条有向边的带非负权图,请你计算从 SS 出发,到每个点的距离。

数据保证你能从 SS 出发到任意点。

输入输出格式

输入格式:

第一行为三个正整数 N, M, SN,M,S。 第二行起 MM 行,每行三个非负整数 u_i, v_i, w_iui?,vi?,wi?,表示从 u_iui? 到 v_ivi? 有一条权值为 w_iwi? 的边。

输出格式:

输出一行 NN 个空格分隔的非负整数,表示 SS 到每个点的距离。

输入输出样例

输入样例#1:

4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4

输出样例#1:

0 2 4 3

说明

样例解释请参考 数据随机的模板题

1≤N≤100000;

1≤M≤200000;

S=1;

1≤ui?,vi?≤N;

0≤wi?≤10^9,

0≤∑wi?≤10^9。

本题数据可能会持续更新,但不会重测,望周知。

2018.09.04 数据更新 from @zzq

解题思路:堆优化Dijkstra算法,其实就是降低了每次去查找当前dis数组中最小值的时间,时间复杂度由原来的O(|V|2)降为O(|E|log|V|)。

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1e5+5;
 4 int n,m,s,u,v,w,x,y,z,len,dis[maxn];vector<int> v1[maxn],v2[maxn];
 5 priority_queue< pair<int,int> > que;//最大堆优先队列
 6 void Dijkstra(){
 7     while(!que.empty())que.pop();
 8     dis[s]=0;que.push(make_pair(-dis[s],s));//加上负号实现最大堆,便于取出最短路径
 9     while(!que.empty()){
10         x=que.top().second,len=-que.top().first;que.pop();
11         if(dis[x]<len)continue;//过滤掉已经更新过的顶点,表示当前顶点x到源点的距离dis[x]
12         for(size_t j=0;j<v1[x].size();++j){
13             y=v1[x][j],z=v2[x][j];
14             if(dis[x]+z<dis[y])dis[y]=dis[x]+z,que.push(make_pair(-dis[y],y));
15         }
16     }
17 }
18 int main(){
19     while(~scanf("%d%d%d",&n,&m,&s)){
20         for(int i=0;i<=n;++i)v1[i].clear(),v2[i].clear();
21         for(int i=0;i<=n;++i)dis[i]=2e9;
22         while(m--){
23             scanf("%d%d%d",&u,&v,&w);
24             v1[u].push_back(v);
25             v2[u].push_back(w);
26         }
27         Dijkstra();
28         for(int i=1;i<=n;++i)printf("%d%c",dis[i],i==n?‘\n‘:‘ ‘);
29     }
30     return 0;
31 }

原文地址:https://www.cnblogs.com/acgoto/p/9865318.html

时间: 2024-10-12 19:31:52

luogu P3371 & P4779 ---单源最短路径spfa & 最大堆优化Dijkstra的相关文章

[C++]单源最短路径:迪杰斯特拉(Dijkstra)算法(贪心算法)

1 Dijkstra算法 1.1 算法基本信息 解决问题/提出背景 单源最短路径(在带权有向图中,求从某顶点到其余各顶点的最短路径) 算法思想 贪心算法 按路径长度递增的次序,依次产生最短路径的算法 [适用范围]Dijkstra算法仅适用于[权重为正]的图模型中 时间复杂度 O(n^3) 补充说明 亦可应用于[多源最短路径](推荐:Floyd算法(动态规划,O(n^3))) Dijkstra 时间复杂度:O(n^3) 1.2 算法描述 1.2.1 求解过程(具体思路) 1.2.2 示例 1.2

【20171109】Luogu P3371 【模板】单源最短路径--SPFA

题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三个整数Fi.Gi.Wi,分别表示第i条有向边的出发点.目标点和长度. 输出格式: 一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度(若S=i则最短路径长度为0,若从点S无法到达点i,则最短路径长度为2147483647) 输入输出样例 输入样例#1:复制 4 6 1

[模板]洛谷T3371 单源最短路径 SPFA+手工队列类

一年之后又重新学习此算法...233... 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<ctime> 6 #include<cstdlib> 7 8 #include<string> 9 #include<stack> 10 //#include<queue> 11

单源最短路径算法——Bellman-ford算法和Dijkstra算法

 BellMan-ford算法描述 1.初始化:将除源点外的所有顶点的最短距离估计值 dist[v] ← +∞, dist[s] ←0; 2.迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离:(运行|v|-1次) 3.检验负权回路:判断边集E中的每一条边的两个端点是否收敛.如果存在未收敛的顶点,则算法返回false,表明问题无解:否则算法返回true,并且从源点可达的顶点v的最短距离保存在 dist[v]中. 1 BELLMAN-FORD

单源最短路径----Dijkstra算法

#include <iostream> #include <vector> #define INFINITY 32768 #define VERTEX_MAX 50 using namespace std; typedef char VertexType; //顶点类型 typedef int AdjType; //边的关系类型 typedef struct { VertexType vertex[VERTEX_MAX]; //顶点集 AdjType arcs[VERTEX_MAX

数据结构:单源最短路径--Dijkstra算法

Dijkstra算法 单源最短路径 给定一带权图,图中每条边的权值是非负的,代表着两顶点之间的距离.指定图中的一顶点为源点,找出源点到其它顶点的最短路径和其长度的问题,即是单源最短路径问题. Dijkstra算法 求解单源最短路径问题的常用方法是Dijkstra(迪杰斯特拉)算法.该算法使用的是贪心策略:每次都找出剩余顶点中与源点距离最近的一个顶点. 算法思想 带权图G=<V,E>,令S为已确定了最短路径顶点的集合,则可用V-S表示剩余未确定最短路径顶点的集合.假设V0是源点,则初始 S={V

P3371 【模板】单源最短路径 如题

P3371 [模板]单源最短路径 时空限制1s / 128MB 题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三个整数Fi.Gi.Wi,分别表示第i条有向边的出发点.目标点和长度. 输出格式: 一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度(若S=i则最短路径长度为0,若从点S无法到达点i,则最短路径长度为214

Luogu 3371【模板】单源最短路径

Luogu 3371[模板]单源最短路径 第一次写博客用图论题来试一试 接下来是正文部分 题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三个整数Fi.Gi.Wi,分别表示第i条有向边的出发点.目标点和长度. 输出格式: 一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度 (若S=i则最短路径长度为0,若从点S无法到达

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

P3371 [模板]单源最短路径(弱化版) 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 10005; 4 struct edge { 5 int v, w; 6 }; 7 vector<edge> maps[maxn]; 8 int dis[maxn]; 9 bool vis[maxn]; 10 int n, m, s; 11 void add(int u, int v, int w) {