首页 > 编程语言 >P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)

P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)

时间:2023-06-20 11:32:56浏览次数:53  
标签:松弛 队列 队首 路径 SPFA C++ 单源 入队 abcdefgd


题目背景

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

题目描述

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

输入格式

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

接下来 m 行每行包含三个整数 u,v,w,表示一条 P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_出队

输出格式

输出一行 n 个整数,第 i 个表示 s 到第 i 个点的最短路径,若不能到达则输出 P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_出队_02

输入输出样例

输入 #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

说明/提示

【数据范围】

对于 P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_出队_03 的数据:P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_数据_04P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_出队_05
对于 P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_出队_06 的数据:P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_最短路径_07P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_数据_08
对于 P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_数据_09 的数据:P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_数据_10P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_出队_11
对于 P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_出队_12 的数据:P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_出队_13P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_最短路径_14,保证数据随机。

对于真正 P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_出队_12 的数据,请移步 P4779。请注意,该题与本题数据范围略有不同。

样例说明:

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

思路

模拟过程(摘自SPFA 算法详解(最短路径)有删改)

P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_最短路径_16


首先建立起始点a到其余各点的最短路径表格

a

b

c

d

e

f

g

d[i]

0

inf

inf

inf

inf

inf

inf

首先源点a入队,当队列非空时:

    队首元素(a)出队,对以a为起始点的所有边的终点依次进行松弛操作(此处有b,c,d三个点),此时路径表格状态为:

a

b

c

d

e

f

g

d[i]

0

24

8

15

inf

inf

inf

在松弛时三个点的最短路径估值变小了,而这些点队列中都没有出现,这些点需要入队,此时,队列中新入队了三个结点b,c,d

队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e点),此时路径表格状态为:

a

b

c

d

e

f

g

d[i]

0

24

8

15

30

inf

inf

在最短路径表中,e的最短路径估值也变小了,e在队列中不存在,因此e也要入队,此时队列中的元素为c,d,e

队首元素c点出队,对以c为起始点的所有边的终点依次进行松弛操作(此处有e,f两个点),此时路径表格状态为:

a

b

c

d

e

f

g

d[i]

0

24

8

15

15

11

inf

在最短路径表中,e,f的最短路径估值变小了,e在队列中存在,f不存在。因此e不用入队了,f要入队,此时队列中的元素为d,e,f

队首元素d点出队,对以d为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:

a

b

c

d

e

f

g

d[i]

0

24

8

15

15

11

19

队首元素e点出队,对以d为起始点的所有边的终点依次进行松弛操作,在最短路径表中,g的最短路径估值没有变小(松弛不成功),没有新结点入队,队列中元素为f,g

队首元素f点出队,对以f为起始点的所有边的终点依次进行松弛操作(此处有d,e,g三个点),此时路径表格状态为:

a

b

c

d

e

f

g

d[i]

0

24

8

15

13

11

14

在最短路径表中,e,g的最短路径估值又变小,队列中无e点,e入队,队列中存在g这个点,g不用入队,此时队列中元素为g,e

队首元素g点出队,对以g为起始点的所有边的终点依次进行松弛操作(此处只有b点),此时路径表格状态为:

a

b

c

d

e

f

g

d[i]

0

17

8

15

13

11

14

在最短路径表中,b的最短路径估值又变小,队列中无b点,b入队,此时队列中元素为e,b队首元素e点出队,对以e为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:

a

b

c

d

e

f

g

d[i]

0

17

8

15

13

11

14

在最短路径表中,g的最短路径估值没变化(松弛不成功),此时队列中元素为b

队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e这个点),此时路径表格状态为:

a

b

c

d

e

f

g

d[i]

0

17

8

15

13

11

14

在最短路径表中,e的最短路径估值没变化(松弛不成功),此时队列为空了

最终a到g的最短路径为14

a

b

c

d

e

f

g

d[i]

0

17

8

15

13

11

14

Code

图的存储采用链式向前星,不懂请点击<这里>

(看完模拟过程和链式向前星的你可以自己写出来么,建议先自己上手试试,代码很简单。)

#include<bits/stdc++.h>//SPFA算法
using namespace std;
#define INF (1<<31)-1
class node
{
public:
	int to, next, w;
}edge[500010];
int n, m, s, u, v, w, cnt = 0, head[10010],  vis[10010];
long long dis[10010];
queue<int> a;
void add(int u, int v, int w)//链式向前星
{
	edge[++cnt].w = w;
	edge[cnt].to = v;
	edge[cnt].next = head[u];
	head[u] = cnt;
}
void SPFA()
{
	for (int i = 1; i <= n; i++)
		dis[i] = INF;
	a.push(s);
	vis[a.front()] = 1;
	dis[s] = 0;//源点到自身的距离为零
	while (!a.empty())
	{
		for (int i = head[a.front()]; i; i = edge[i].next)//对相连的点进行松弛操作
			if (dis[edge[i].to] > dis[a.front()] + edge[i].w)//更新距离
			{
				dis[edge[i].to] = dis[a.front()] + edge[i].w;
				if (!vis[edge[i].to])//队列中无此结点
				{
					a.push(edge[i].to);
					vis[edge[i].to] = 1;
				}
			}
		vis[a.front()] = 0;
		a.pop();
	}
}
int main()
{
	cin >> n >> m >> s;
	for (int i = 1; i <= m; i++)//存图
	{
		cin >> u >> v >> w;
		add(u, v, w);
	}
	SPFA();
	for (int i = 1; i <= n; i++)
		cout << dis[i]<<" ";
	return 0;
}
如果你看懂了SPFA,那么最后这张图送给你:

P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)_最短路径_17

死因:毒瘤数据。

所以在没有负环(某个重复进入队列的节点)的情况下不建议使用SPFA,请放心随机数据的话肯定会有,出题人要是想卡SPFA那就请换Dijkstra再来!


标签:松弛,队列,队首,路径,SPFA,C++,单源,入队,abcdefgd
From: https://blog.51cto.com/u_16165815/6521652

相关文章

  • C++ primer plus学习之第二章
    1.引用:intival=1024;int&refval=ival;//正确,refval时ival的别名int&re;//错误,引用必须被初始化int&ii=42;//错误:不能为非常量引用绑定字面值constint&ii=42;//正确:可以为常量引用绑定字面值2.初始化空指针int*p=0;int*p=NULL;int*p=nullptr;//最好用这个任何非零指......
  • 总结C++中#include<>和#include""的区别
    查找目录不同1、#include<>编译器直接从系统类库目录里查找头文件比如在vs中,使用#include<>编译器会直接在vs安装目录下在编译器自带的库文件中进行搜索。如果类库目录下查找失败,编译器会终止查找,直接报错:Nosuchfileordirectory.如果我们自定义一个头文件"aaa.h",将其放在......
  • CCF_201912-1 报数(C++_模拟)
    思路代码可能写的有点啰嗦冗余,写的时候有点急写完一节就直接复制粘贴了蛤蛤蛤,所以导致中间有些代码比较重复。Code#include<bits/stdc++.h>//模拟usingnamespacestd;intn,sum=0,a,b,c,d;booljudge(ints){ inttemp=s; if(temp%7==0) return0; while......
  • 数据结构代码整理_基于邻接表的拓扑排序(C++_DFS_BFS_递归)
    目录Chat图解基于栈实现(dfs)基于队列实现(bfs)基于递归实现(dfs)Chat1.代码所属的类在数据结构代码整理_基于邻接表存储结构的有向图的实现(C++)2.拓扑排序的思想就是不断找入度为0的节点并将其输出并标记,标记后与他相连的节点的入度都会减一,不断进行标记直至所有的节点都被输出为止......
  • Educational Codeforces Round 82 (Rated for Div. 2)_A. Erasing Zeroes(C++_模拟)
    Youaregivenastring.Eachcharacteriseither0or1.Youwantall1’sinthestringtoformacontiguoussubsegment.Forexample,ifthestringis0,1,00111or01111100,thenall1’sformacontiguoussubsegment,andifthestringis0101,100001o......
  • PAT (Advanced Level) Practice_1095 Cars on Campus (30分)(C++_模拟)
    ZhejiangUniversityhas8campusesandalotofgates.Fromeachgatewecancollectthein/outtimesandtheplatenumbersofthecarscrossingthegate.Nowwithalltheinformationavailable,youaresupposedtotell,atanyspecifictimepoint,thenu......
  • P1969 积木大赛(C++_贪心_模拟)
    题目描述春春幼儿园举办了一年一度的“积木大赛”。今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是。在搭建开始之前,没有任何积木(可以看成n块高度为0的积木)。接下来每次操作,小朋友们可以选择一段连续区间,然后将第第L块到第R......
  • PAT_Advanced Level_1083 List Grades (25分)(C++_快排)
    GivenalistofNstudentrecordswithname,IDandgrade.Youaresupposedtosorttherecordswithrespecttothegradeinnon-increasingorder,andoutputthosestudentrecordsofwhichthegradesareinagiveninterval.InputSpecification:Eachinput......
  • 【蓝桥杯_真题演练】第十届C/C++省赛B组_H-等差数列(C++_gcd_数论)
    ProblemProcess在输入的时候先去重,然后进行排序,至于他们的公差p则需要计算每两个相邻数值之间差值的最大公因数,最终的结果应该是Code#include<bits/stdc++.h>usingnamespacestd;#definelllonglongintn,a[100010],cnt;set<int>s;intgcd(inta,intb){ returnb==......
  • P1062 数列(C++_数论)
    题目描述给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当k=3时,这个序列是:(该序列实际上就是:)请你求出这个序列的第N项的值(用10进制数表示)。例如,对于k=3,N=100,正确答案应该是981。输入格式2个正整数,用一个空格隔开:输出格式1个正整......