spfs求最短路
题目描述:
解析:
这其实是对bellman_ford的优化,我们回忆下bellman_ford的解法:每次会记录上一次更新的状态,然后每个点都会通过与他相连的节点来更新答案,直至更新k次就可得出答案。这个解法其实重复了很多无效的更新,因为并不是每次更新都能得出更小的答案,spfa就是从这里入手来进行优化。
单纯看spfa的代码你会发现与dijkstra的代码相似度非常高,spfa没用优先队列,用了普通的队列,但st的取值规律发生了变化。dijkstra的st数组是存中继节点的,每个中继节点用完了就不能再当做中继节点用了,而spfa则不同,他的中继节点用完了还能再用,为什么?
因为dijkstra用完了一次中继节点之后其中继节点都能取得最小值,都是用这个最小值来更新的,后面就不必再用该中继节点来更新了,但spfa则不同,由于没用优先队列,所以其中继节点的dist值不能保证为最小值,故要重复使用多次才行,但这个重复使用的前提是这个中继节点得能使得最终节点取得更小值,这就是对bellman_ford的优化,有点像bfs。
由于是对bellman_ford的优化,故最坏的时间复杂度为O(n*m),所以容易被卡。
在时间复杂度允许的条件下,spfa能解决dijkstra的题目,但能用dijkstra解决的题目最好别用spfa,容易被卡常。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=1e5+10;
int h[N],e[M],ne[M],w[M],idx=0;
int n,m,dist[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void spfa()
{
memset(dist,0x3f,sizeof(dist));
dist[1]=0;
st[1]=true;
queue<int> q;
q.push(1);
while(q.size())
{
int 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;
}
}
}
}
}
int main()
{
scanf("%d%d",&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(dist[n]==0x3f3f3f3f) printf("impossible");
else printf("%d",dist[n]);
return 0;
}
spfa判断负环
题目描述:
解析:
无非是在spfa代码基础上加了统计路径边的个数,如果大于或等于n就说明有负环。当然,由于是判断负环,所以每个点都有可能有负环,故在开始时每个点都要加进去。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e3+10,M=10010;
int n,m;
bool st[N];
int dist[N],cnt[N];
int e[M],ne[M],h[N],w[M],idx;
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++)
{
st[i]=true;
q.push(i);
}
while(q.size())
{
int 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];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n) return true;
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
int main()
{
scanf("%d%d",&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;
}