Bellman-Ford算法:
Bellman-Ford算法用于解决带有负权边的单源最短路径问题。其基本思想是通过不断地松弛边来逐步求解最短路径。算法的主要步骤如下:
- 初始化:将源点到各个顶点的距离初始化为无穷大,源点的距离初始化为0。
- 重复更新:重复执行以下步骤|V|-1次(其中|V|是顶点的数量):
- 对于图中的每条边(u, v),尝试以当前最短路径长度到达顶点v,如果从源点s经过u再到v的路径长度更短,则更新v的最短路径长度为s到u的最短路径长度加上(u, v)的权值。
- 检测负权回路:检查所有边,如果在第|V|次松弛操作后,仍然存在顶点的最短路径长度可以继续减小,则说明存在负权回路。
Bellman-Ford算法的时间复杂度为O(|V| * |E|),其中|V|是顶点的数量,|E|是边的数量。
SPFA算法(Shortest Path Faster Algorithm):
SPFA算法是一种改进的最短路径算法,类似于Bellman-Ford算法,但是在实际应用中通常运行得更快。其基本思想是使用队列来保存待更新的顶点,并通过只对需要更新的顶点进行松弛操作来减少不必要的计算。算法的主要步骤如下:
- 初始化:将源点加入队列,并将源点到各个顶点的距离初始化为无穷大,源点的距离初始化为0。
- 重复更新:从队列中取出一个顶点u,遍历与u相邻的所有顶点v:
- 如果以u为中介点,可以使得源点s到v的路径长度更短,则更新v的最短路径长度为s到u的最短路径长度加上(u, v)的权值,并将v加入队列。
- 重复步骤2,直到队列为空。
SPFA算法在最坏情况下的时间复杂度是O(|V| * |E|),但是在平均情况下通常运行得更快,特别是在稀疏图中。
洛谷 P3385 负环
AC code
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
vector<PII> vv[3010];
int T;
int n,m;
int u,v,w;
queue<int> q;
int d[2010];
int vis[2010];
int cnt[2010];
inline bool spfa(){
memset(d,0x3f,sizeof d);
memset(vis,0,sizeof vis);
memset(cnt,0,sizeof cnt);
d[1]=0;q.push(1);vis[1]=1;
while(q.size()){
int t=q.front();q.pop();vis[t]=0;
for(auto ed:vv[t]){
int a=ed.first,b=ed.second;
if(d[a]>d[t]+b){
d[a]=d[t]+b;
cnt[a]=cnt[t]+1;
if(cnt[a]>=n) return true;判断负环
if(!vis[a]) q.push(a),vis[a]=1;
}
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
cin>>n>>m;
for(int i=0;i<m;i++){
cin>>u>>v>>w;
if(w>=0) vv[u].push_back({v,w}),vv[v].push_back({u,w});
else vv[u].push_back({v,w});
}
if(spfa()) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
for(int i=1;i<=n;i++) vv[i].clear();
}
return 0;
}