使用题型
该算法依旧是求单源最短路的算法,之前学了ford算法由于每次循环都是按照最坏结果,即每次循环只有一条边被确定并在后续操作中无需更改(该算法是保证每一次循环至少有一条边被确定)故需要循环n*m次其中有些循环是浪费了的,故有后人简化了该算法,这就是SPFA的来历
思想
d[i]指从起点到i点的最短路径,e[i].w指第i条边的权值,基于ford算法上,用队列来存储需要处理的点,每一次弹出队列首元素p,判断d[j]与d[p]+e[i].w的大小来考虑是否要更改d[j]的值,若更改,j点入队。如此处理到队列为空时,代表已处理所有有变动的边即图中每个点到起点的最短路径已求出,该算法便有效解决了ford算法中有无用循环的时间浪费,如程序:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MM 1000000005
#define N 100001
#define M 500001
struct node{
int v,w,next;
}e[M*2];
queue <int> q;
int i,j,k,n,ai,m,bi,ci;
int d[N],first[N];
bool f[N];
void add(int u1,int v1,int w1){//添加以u1为起点,v1为终点,权值w1的边(链表存储的方式)
++k;
e[k].w=w1;
e[k].v=v1;
e[k].next=first[u1];
first[u1]=k;
}
void spfa()
{
while(!q.empty())
{
int p=q.front();//弹出队列首元素
q.pop();//删除队列首元素
f[p]=1;
for(i=first[p];i;i=e[i].next)
{
int j=e[i].v;
if(d[j]>d[p]+e[i].w)//判断
{
d[j]=d[p]+e[i].w;
if(f[j])
{
q.push(j);
f[j]=0;
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
memset(first,0,sizeof(first));
k=0;
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&ai,&bi,&ci);
add(ai,bi,ci);
add(bi,ai,ci);
}
for(i=1;i<=n;i++) d[i]=MM;
memset(f,1,sizeof(f));
d[1]=0;
q.push(1);f[1]=0;
spfa();
printf("%d",d[n]);
return 0;
}