spfa算法主要是处理有负边的图,没有负边的图用dij来处理。
spfa的思想是:用更新过的点来改变距离。
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1e5 + 10;
int e[N],ne[N],h[N],idx,w[N];
int d[N];
bool st[N];
int n,m;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void spfa()
{
memset(d,0x3f,sizeof d);
d[1]=0;
queue<int> q;
q.push(1);
st[1]=true;
while(q.size())
{
auto t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];~i;i=ne[i])
{
int j=e[i];
if(d[j]>d[t]+w[i])
{
d[j]=d[t]+w[i];
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
spfa();
if(d[n]==0x3f3f3f3f) puts("impossible");
else printf("%d\n",d[n]);
return 0;
}
spfa判断负环
在spfa原来模板的基础上,加上cnt数组,用来记录每个点更新时用到的点的数量。
如果当前点被n个边更新,那么说明从起点到当前点通过了n+1条边,根据抽屉原理,n个点最多有n-1条边,那么就说明,这条通路有环,又因为求的是最短路,它可以被这样更新,就说明有负环。
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 2010 , M = 10010;
int e[M],ne[M],w[M],h[N],idx;
int d[N];
bool st[N];
int n,m;
int cnt[N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool spfa()
{
queue<int> q;
for(int i=1;i<=n;i++)
{
q.push(i);
st[i]=true;
}
while(q.size())
{
auto t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];~i;i=ne[i])
{
int j=e[i];
if(d[j]>d[t]+w[i])
{
d[j]=d[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n) return true;
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
if(spfa()) puts("Yes");
else puts("No");
return 0;
}