问题链接:AcWing 851. spfa求最短路
问题描述
spfa算法是对bellman-ford算法的改进,bellman-ford算法比较笨,要遍历所有边来更新,其实如果当前点没有被更新的话,就不用用当前点来更新他所连接的点了。我们只需要每次更新一个点后,继续更新该点连接的点即可。
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e5+10,M=1e5+10,INF=0x3f3f3f3f;struct E{int v,w,nxt;
};
E edge[M];
int head[N], idx=0;
int n,m;
int dist[N];
int st[N];void init(){for(int i=0;i<=n;i++){head[i]=-1;dist[i]=INF;}
}
void add(int u,int v,int w){edge[idx].v=v;edge[idx].w=w;edge[idx].nxt=head[u];head[u]=idx++;
}
int spfa(){dist[1]=0;st[1]=1;queue<int> q;q.push(1);while(!q.empty()){int t=q.front();q.pop();st[t]=0;for(int i=head[t];~i;i=edge[i].nxt){int v=edge[i].v;int w=edge[i].w;if(dist[v]>dist[t]+w){dist[v]=dist[t]+w;if(!st[v]){q.push(v);st[v]=1;}}}}return dist[n];
}
int main(){cin>>n>>m;init();while(m--){int u,v,w;scanf("%d%d%d",&u,&v,&w);add(u,v,w);}int k=spfa();if(k<INF/2) cout<<k;else puts("impossible");return 0;
}
我这里用的是链式前向星来存图
问题链接:AcWing 852. spfa判断负环
问题描述
正如bellman-ford算法中提到的,一个点到其余点的最短路径,最长需要经过n-1条边,所以如果有大于等于n条边,则说明一定有环。注意从单元点出发,有可能找不到环,因为环不一定在最短路径上。
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e5+10,M=1e5+10,INF=0x3f3f3f3f;struct E{int v,w,nxt;
};
E edge[M];
int head[N], idx=0;
int n,m;
int dist[N];
int st[N];
int cnt[N];void init(){for(int i=0;i<=n;i++){head[i]=-1;dist[i]=INF;}
}
void add(int u,int v,int w){edge[idx].v=v;edge[idx].w=w;edge[idx].nxt=head[u];head[u]=idx++;
}
bool spfa(){dist[1]=0;queue<int> q;for(int i=1;i<=n;i++){q.push(i);st[i]=true;} while(!q.empty()){int t=q.front();q.pop();st[t]=0;for(int i=head[t];~i;i=edge[i].nxt){int v=edge[i].v;int w=edge[i].w;if(dist[v]>dist[t]+w){cnt[v]=cnt[t]+1;if(cnt[v]>=n) return false;dist[v]=dist[t]+w;if(!st[v]){q.push(v);st[v]=1;}}}}return true;
}
int main(){cin>>n>>m;init();while(m--){int u,v,w;scanf("%d%d%d",&u,&v,&w);add(u,v,w);}int k=spfa();if(!k) puts("Yes");else puts("No");return 0;
}