图 SPFA算法

使用题型

该算法依旧是求单源最短路的算法,之前学了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;
}

猜你喜欢

转载自blog.csdn.net/weixin_44336566/article/details/85368981