题目背景
本题测试数据为随机数据,在考试中可能会出现构造数据让SPFA不通过,如有需要请移步 P4779。
题目描述
如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度。
输入格式
第一行包含三个整数 n,m,sn,m,s,分别表示点的个数、有向边的个数、出发点的编号。
接下来 mm 行每行包含三个整数 u,v,wu,v,w,表示一条 u \to vu→v 的,长度为 ww 的边。
输出格式
输出一行 nn 个整数,第 ii 个表示 ss 到第 ii 个点的最短路径,若不能到达则输出 2^{31}-1231−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\%20% 的数据:1\le n \le 51≤n≤5,1\le m \le 151≤m≤15;
对于 40\%40% 的数据:1\le n \le 1001≤n≤100,1\le m \le 10^41≤m≤104;
对于 70\%70% 的数据:1\le n \le 10001≤n≤1000,1\le m \le 10^51≤m≤105;
对于 100\%100% 的数据:1 \le n \le 10^41≤n≤104,1\le m \le 5\times 10^51≤m≤5×105,1\le u,v\le n1≤u,v≤n,w\ge 0w≥0,\sum w< 2^{31}∑w<231,保证数据随机。
对于真正 100\%100% 的数据,请移步 P4779。请注意,该题与本题数据范围略有不同。
#include<bits/stdc++.h> using namespace std; int vis[5000005]; int low[5000005]; int const inf = 2147483647; int n, k,p,q;//k指边的数量; //链式前向星 struct node { int to; int v; int next; }; struct node edge[5000005]; int head[5000005]; int cnt = 0; void add(int a, int b, int c) { cnt++; edge[cnt].v = c;//边权值 edge[cnt].to = b;//表示第i条边的终点 edge[cnt].next = head[a];//表示与第i条边同起点的下一条边的存储位置 head[a] = cnt; } void Dijkstra() { for (int i = 1; i <= n; i++) { low[i] = inf; vis[i] = 0; }//初始化 low[p] = 0; int s = p; for(int i=1; i<=n; i++) { int Min = inf,s=-1; for (int i = 1; i <= n; i++) { if (vis[i]==0 && Min > low[i]) { Min = low[i]; s = i; } } vis[s] = 1; //更新数据 for (int i = head[s]; i != 0; i = edge[i].next) { int a = s, b = edge[i].to,c= edge[i].v; if (vis[b]==0 && low[b] > low[a] + c) { low[b] = low[a] +c; } } } for(int i=1; i<=n; i++)//表示从起始点p到i点的最短距离 cout<<low[i]<<" "; //cout<<endl; } int main() { cin >> n >> k>>p; int a, b, c; for (int i = 1; i <= k; i++) { cin >> a >> b >> c; add(a, b, c); } Dijkstra(); }
如果将链式前向星中的add函数改为:
void add(int a, int b, int c)
{
cnt++;
edge[cnt].v = c;//边权值
edge[cnt].to = a;//表示第i条边的起点
edge[cnt].next = head[b];//表示与第i条边同中点的上一条边的存储位置
head[b] = cnt;
}
则在结尾可以得到low[i]为i点到起始点的最短距离
#include<bits/stdc++.h> using namespace std; int vis[500005]; int low[500005]; int const inf = 2147483647; int n, k,p,q;//k指边的数量; //优先队列 struct note { int s; int c; bool operator<(const note &x) const //重载<操作符,可对两个note使用<操作符进行比较 { return x.c<c; }//进行了排序 }; //链式前向星 struct node { int to; int v; int next; }; struct node edge[500005]; int head[500005]; int cnt = 0; void add(int a, int b, int c) { cnt++; edge[cnt].v = c;//边权值 edge[cnt].to = b;//表示第i条边的终点 edge[cnt].next = head[a];//表示与第i条边同起点的下一条边的存储位置 head[a] = cnt; } void Dijkstra() { for (int i = 1; i <= n; i++) { low[i] = inf; vis[i] = 0; }//初始化 low[p] = 0; priority_queue<note> w; w.push({p,0});//插入{p,0} while (w.size()!=0)//元素数量 { int s=w.top().s;//访问堆顶元素 w.pop();//删除优先级元素 if(vis[s]==1) continue; vis[s] = 1; for (int i = head[s]; i != 0; i = edge[i].next) { int a = s, b = edge[i].to, c = edge[i].v; if ( low[b] > c + low[a]) { low[b] = low[a] + c; if(vis[b]==0) w.push({b,low[b]}); } //cout<<s<<" "<<low[a]<<" "<<c<<" "<<low[b]<<endl; } } for(int i=1;i<=n;i++) cout<<low[i]<<" "; } int main() { cin >> n >> k>>p; int a, b, c; for (int i = 1; i <= k; i++) { cin >> a >> b >> c; add(a, b, c); } Dijkstra(); }