Bellman-Ford
存图:边集数组/二维vector/链式前向星
最多松弛n-1轮
每松弛一轮至少可以确定一个点的最短距离,每一轮至少有一条边被松弛掉
不能求负权回路,但可以检验负环
模板
C++
#include<bits/stdc++.h>
using namespace std;
#define inf 1001
//边集数组----->带权有向图为例
int n,m,s; //n<=100 -1000<边权<1000
struct Edge{
int start,end;
int w;
}e[10005];
int dis[105];
void Ford(){
int u,v,flag;
for(int i=1;i<n;++i){//最多执行n-1轮
flag=0;
for(int j=1;j<=m;++j){
u=e[j].start;
v=e[j].end;
if(dis[u]+e[j].w<dis[v]){
dis[v]=dis[u]+e[j].w;
flag=1;
}
}
if(flag==0) break;
}
}
int main(){
cin>>n>>m;
int x,y,wi;
for(int i=1;i<=m;++i){
cin>>x>>y>>wi;
e[i]=(Edge){x,y,wi};
}
for(int i=1;i<=n;++i){
dis[i]=inf;
}
cin>>s;//起点
dis[s]=0;
//bellman-Ford
Ford();
for(int i=1;i<=n;++i){
cout<<dis[i]<<" ";
}
return 0;
}
检验是否有负权回路:如果进行了n轮还能被松弛,就说明有负权回路
C
#include<bits/stdc++.h>
using namespace std;
#define inf 1001
//边集数组----->带权有向图为例
int n,m,s; //n<=100 -1000<边权<1000
struct Edge{
int start,end;
int w;
}e[10005];
int dis[105];
bool Ford(){
int u,v,f=0;
for(int i=1;i<=n;++i){//执行n轮
for(int j=1;j<=m;++j){
u=e[j].start;
v=e[j].end;
if(dis[u]+e[j].w<dis[v]){
dis[v]=dis[u]+e[j].w;
if(i==n) f=1;
}
}
}
if(f==1) return true;
else return false;
}
int main(){
cin>>n>>m;
int x,y,wi;
for(int i=1;i<=m;++i){
cin>>x>>y>>wi;
e[i]=(Edge){x,y,wi};
}
for(int i=1;i<=n;++i){
dis[i]=inf;
}
cin>>s;//起点
dis[s]=0;
//bellman-Ford
if(Ford()){
cout<<"有负环"<<endl;
}
else{
for(int i=1;i<=n;++i){
cout<<dis[i]<<" ";
}
}
return 0;
}
优化:SPFA
最好时间复杂度 O(|E|) 平均时间复杂度会小 最坏时间复杂度不变O(|V||E|)
不稳定
在题目所设图中不出现负边权时,各大比赛的出题人均会卡SPFA算法,因为SPFA算法玄学的时间复杂度,给人一种骗分的感觉,所以为了尊重选手,尊重Diikstra算法,会卡SPFA.即SPFA已经死。
优先Dijkstra 有负边权再使用SPFA
SPFA能判断带环负权图
例题
需要判断负环
C++
#include<bits/stdc++.h>
using namespace std;
using ll=long long ;
//链式前向星写Dijkstra
int n,m,cnt; //n<100 0<权值<1000
int h[100005];
struct Edge{
int to,w,next;
}e[500005]; //100个点 最多100*(100-1)条边
ll dis[100005];
int cur[100005];
int v[100005];
void add(int u,int v,int w){
e[cnt].to=v;
e[cnt].w=w;
e[cnt].next=h[u];
h[u]=cnt;
cnt++;
}
bool spfa(int x){//堆优化
for(int i=1;i<=n;++i) {
dis[i]=INT_MAX;
}
dis[x]=0;
queue<int> q;
int u,k;
v[x]=1;
q.push(x);
while(!q.empty()){
u=q.front();
q.pop();
v[u]=0;
for(int i=h[u];i!=-1;i=e[i].next){
k=e[i].to;
if(dis[k]>dis[u]+e[i].w){
dis[k]=dis[u]+e[i].w;
cur[k]=cur[u]+1;
if(cur[k]>=n) return false;
if(v[k]==0){
q.push(k);
v[k]=1;
}
}
}
}
return true;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
memset(h,-1,sizeof h);
int s;
//scanf("%d %d %d",&n,&m,&s);
cin>>n>>m>>s;
int x,y,w;
for(int i=1;i<=m;++i){
//scanf("%d %d %d",&x,&y,&w);
cin>>x>>y>>w;
add(x,y,w);
}
if(!spfa(s)){
int ans=INT_MAX;
cout<<ans<<endl;
return 0;
}else{
for(int i=1;i<=n;++i){
//printf("%d ",dis[i]);
cout<<dis[i]<<" ";
}
}
return 0;
}