试题 算法训练 最短路
资源限制
时间限制:1.0s
内存限制:256.0MB
问题描述 给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。输入格式 第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。
输出格式 共n-1行,第i行表示1号点到i+1号点的最短路。 样例输入 3 3 1 2 -1 2 3 -1 3 1 2
SPFA算法简介
全名为shortest path faster algorithm(最短路径快速算法).它的算法原理和bellman算法相似,但是它的速度远超其他最短路径算法。平均时间复杂度仅为O(e),即与图中的边成正比。反观常用的dijkstra算法,时间复杂度达到了O(n^2),虽然在最坏的情况下,它的复杂度会大大增加,接近于bellman算法,但是o(E)的时间复杂度还是太香了,这表现了SPFA算法极其突出的优势。
它的基本算法思路如下:
1.首先基于顶点个数定义两个数组,一个dis表示到源节点目前的最短距离,一个vis表示顶点是否已经入队。
2.将dis数组用循环初始化为一个很大的数字(表示“无穷大”),这一步是为了之后的路径比较。
3.将源节点初始化入队(dis=0,vis=true)
4.while循环,队列不为空时,不断查找队头能松弛(即减小路径)的节点,并将其入队(vis=true),队头查找完后出队(vis=false)。
5.运行完就结束了~
例题参考代码:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
class vertex
{
public:
int v;
int d;
vertex(int a, int b)
{
v = a;
d = b;
}
};
vector <vertex> vec[20005];
int m, n,dis[20005];
bool vis[20005];
void SPFA(int b)
{
for (int i = 1; i <= n; i++)//初始化
{
dis[i] = 500000;
}
int u;
queue <int> s;//定义队列
s.push(b);//源节点入队
dis[b] = 0;
vis[b] = true;
while (!s.empty())
{
u = s.front();
s.pop();//出队
vis[u] = false;
for (int i = 0; i < vec[u].size(); i++)//查找可松弛的节点
{
if (dis[vec[u][i].v] > dis[u] + vec[u][i].d)//更新节点最短路径
{
dis[vec[u][i].v] = dis[u] + vec[u][i].d;
s.push(vec[u][i].v);
vis[vec[u][i].v] = true;
}
}
}
}
void Output()
{
for (int i = 2; i <=n; i++)
{
cout << dis[i]<<endl;
}
}
int main()
{
int x, y, z;
cin >> n >> m;
for (int i = 0; i < m; i++)
{
scanf("%d%d%d",&x,&y,&z);
vec[x].push_back({y,z});
}
SPFA(1);
Output();
return 0;
}