P3371 【模板】单源最短路径(弱化版)
题目背景
本题测试数据为随机数据,在考试中可能会出现构造数据让SPFA不通过,如有需要请移步 P4779。
题目描述
如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度。
输入格式
第一行包含三个整数n,m,s,分别表示点的个数、有向边的个数、出发点的编号。
接下来 m 行每行包含三个整数u,v,w,表示一条u→v 的,长度为 w 的边。
输出格式
输出一行 n 个整数,第 i 个表示 s 到第 i 个点的最短路径,若不能到达则输出 2^31−1。
输入输出样例
输入 #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
说明/提示
【数据范围】
对于 20% 的数据:1≤n≤5,1≤m≤15;
对于 40% 的数据:1≤n≤100,1≤m≤10^4;
对于 70% 的数据:1≤n≤1000,1≤m≤10^5;
对于 00% 的数据:1≤n≤10^4,1≤m≤5×10^5,1≤u,v≤n,w≥0,∑w<23^1,保证数据随机。
Update 2022/07/29:两个点之间可能有多条边,敬请注意。
对于真正100% 的数据,请移步 P4779。请注意,该题与本题数据范围略有不同。
样例说明:
图片1到3和1到4的文字位置调换
思路
也就亿点点想嘎人吧,看不懂Dijkstra算法,学了好久试了试还是错的。尝试了啊哈算法上的Bellman队列优化。虽然AC了,但是感觉还是不太懂这些算法。对所有的边进行n-1轮松弛操作,因为在一个含有n个顶点的图中,任意两点之间的最短路径最多包含n-1边。换句话说,第1轮在对所有的边进行松弛后,得到的是源点最多经过一条边到达其他顶点的最短距离;第2轮在对所有的边进行松弛后,得到的是源点最多经过两条边到达其他顶点的最短距离;第3轮在对所有的边进行松弛后,得到的是源点最多经过一条边到达其他顶点的最短距离......队列优化呢就是只对最短路估计值发生变化了的顶点的所有出边执行松弛操作。书上的解释,我还得细细研究会😩
#include<stdio.h>
#define inf 2147483647
int n,m,s;
int u[500005],v[500005],w[500005];
int first[10005],next[500005];
int dis[10005],book[10005];
int que[500005],head=1,tail=1;
void bell()
{
int i,j,k;
for(i=1;i<=n;i++)
dis[i]=inf;
dis[s]=0;
for(i=1;i<=n;i++)
book[i]=0;
for(i=1;i<=n;i++)
first[i]=-1;
for(i=1;i<=m;i++)
{
scanf("%d %d %d",&u[i],&v[i],&w[i]);
next[i]=first[u[i]];
first[u[i]]=i;
}
que[tail]=s;
tail++;
book[s]=1;
while(head<tail)
{
k=first[que[head]];
while(k!=-1)
{
if(dis[v[k]]>dis[u[k]]+w[k])
{
dis[v[k]]=dis[u[k]]+w[k];
if(book[v[k]]==0)
{
que[tail]=v[k];
tail++;
book[v[k]]=1;
}
}
k=next[k];
}
book[que[head]]=0;
head++;
}
}
int main()
{
scanf("%d %d %d",&n,&m,&s);
bell();
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
}