- admin's blog
【模板】SPFA
- @ 2024-1-7 15:25:53
SPFA
最短路
同样是解决单源最短路径问题的算法,只不过这个算法可以处理负边权问题。
相对于Dijstra的贪心,这个SPFA算法就要稍微简单一点
首先,我去从起点开始走,每一条边只要是能走并且比之前的路径段的我就入队列。
一直走到不能再走为止,此时每一个点与起点的距离都可以算出来了。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+12,inf=2147483647;
int n,m,s,cnt;
int dis[N],vis[N],head[N];
struct {
int to,nex,w;
}edge[N];
void addedge(int u,int v,int w)
{
++cnt;
edge[cnt].nex=head[u];
edge[cnt].to=v;
edge[cnt].w=w;
head[u]=cnt;
}
void spfa(){
queue<int>q;
for(int i=1;i<=n;i++)
{
dis[i]=inf;
vis[i]=0;
}
q.push(s);dis[s]=0;vis[s]=1;
while( !q.empty() )
{
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to;
if( dis[y]>dis[x]+edge[i].w )
{
dis[y]=dis[x]+edge[i].w;
if( !vis[y] )
{
vis[y]=1;
q.push(y);
}
}
}
}
}
int main(){
cin>>n>>m>>s;
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
addedge(u,v,w);
}
spfa();
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
}
最负环
和最短路的求法是很相近的,但只不过我们记录每个节点入队的次数,当入队次数大于了节点各数的时候,就证明从该节点开始走,会沿着某一条路径更新权值,并且当回到该节点的时候,所有边权相加得到的结果为负数,就出现了一个负环。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=6e3+12,inf=1e9+12;
int a[N],head[N],d[N],cnt;
bool vis[N];
int t,u,v,w,n,m;
struct {
int to,nex,w;
}edge[N];
void addedge(int u,int v,int w)
{
cnt++;
edge[cnt]={v,head[u],w};
head[u]=cnt;
}
queue<int>q;
void spfa()
{
while(!q.empty()) q.pop();
a[1]=1;
d[1]=0;
vis[1]=1;
q.push(1);
while( !q.empty() )
{
int y=q.front();
vis[y]=0;
q.pop();
for(int i=head[y];i;i=edge[i].nex)
{
int x=edge[i].to;
if( d[x]>edge[i].w+d[y] )
{
d[x]=edge[i].w+d[y];
if(!vis[x])
{a[x]++;
if( a[x]>=n )
{printf("YES\n");
return;
}
q.push(x);
vis[x]=1;
}
}
}
}
printf("NO\n");
}
int main(){
scanf("%d",&t);
while(t--)
{
cnt=0;
scanf("%d %d",&n,&m);
fill(d+1,d+1+n,inf);
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
memset(head,0,sizeof(head));
while(m--)
{
scanf("%d %d %d",&u,&v,&w);
addedge(u,v,w);
if( w>=0 )
addedge(v,u,w);
}
spfa();
}
}