1.自然语言描述
spfa 算法是bellman-ford算法的队列优化做法,bellman-ford算法中每次松弛会有很多用问更新点去更新邻接的未更新点的情况发生,浪费时间,所以利用队列每次只用已经更新过的点去更新它的邻接点。
2.代码描述
题目:Acwing.851 spfa 求最短路题目链接
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN=1e5+10;
int n,m,h[MAXN],e[MAXN*2],ne[MAXN*2],w[MAXN*2],dist[MAXN],idx;
bool st[MAXN];
void add(int a,int b,int c)
{
e[idx]=b;
ne[idx]=h[a];
w[idx]=c;
h[a]=idx++;
}
int spfa()
{
memset(dist,0x3f,sizeof(dist));
dist[1]=0;
queue<int> q;
q.push(1);
st[1]=true;
while(!q.empty()){
auto t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>dist[t]+w[i]){
dist[j]=dist[t]+w[i];
if(!st[j]){
q.push(j);
st[j]=true;
}
}
}
}
if(dist[n]>=0x3f3f3f3f/2)
return -1;
return dist[n];
}
int main(void)
{
cin>>n>>m;
memset(h,-1,sizeof(h));
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
int ans=spfa();
if(ans==-1)
cout<<"impossible"<<endl;
else
cout<<ans<<endl;
return 0;
}
题目:Acwing.852 spfa 判负环题目链接
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN=1e4+10;
int n,m,h[MAXN],e[2*MAXN],ne[2*MAXN],dist[MAXN],w[2*MAXN],cnt[MAXN],idx;
bool st[MAXN];
//cnt保存到某个点时当前遍历路径长度
void add(int a,int b,int c)
{
e[idx]=b;
ne[idx]=h[a];
w[idx]=c;
h[a]=idx++;
}
bool spfa()
{
//不需要初始化dist:要解决问题是是否存在负环,不关心路径长度
queue<int> q;
for(int i=1;i<=n;i++){//图中可能存在负环是1号点无法到达的,所以把所有点加入队列
q.push(i);
st[i]=true;
}
while(!q.empty()){
auto t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n)//遍历路径长度>=n,说明产生负环
return true;
if(dist[j]>dist[t]+w[i]){//负环上的点就会越更新越小
dist[j]=dist[t]+w[i];
if(!st[j]){
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
int main(void)
{
cin>>n>>m;
memset(h,-1,sizeof(h));
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
if(spfa())
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
return 0;
}