单源最短路 spfa

spfa

今天终于写出来了spfa...

  1. 运用队列的思想,先把起点入队,用对首更新它能够到达的点,更新这些点到起点的伪最短路(因为可能还有更短情况)然后把得到更新的点中不在队列里的加入队列,以便更新其他点。

  2. 当前更新的是伪最短路即可能会有更优情况(比如:起点是1,1到6距离为7,加入队列dis[6]=7,而1到7距离为2,7到6距离为3,会将dis[6]更新为2+3=5。所以一遍一遍一遍一遍查,最后将会是最短路。

  3. 用于单源最短路,时间复杂度O(ke),稀疏图中k约等于2,稠密图。。。emmm还是不要用了吧

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct noid
{
    int to;
    int dis;
    int next;
}edg[510000];
int head[20001],inq[20001],dis[20001],q[5000010];
int n,m,s,num;
void read(int &x)
{
    int f=1;char s;x=0;
    s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=10*x+s-'0';s=getchar();}
    x=x*f;
}//读入优化
void add(int x,int y,int dis)
{edg[++num].dis=dis;
    edg[num].to=y;
    
    edg[num].next=head[x];
    head[x]=num;
}//前向星建图
void spfa()
{
    int blb,cur;
    int he=0;
    int tail=1;
    q[tail]=s;dis[s]=0;
    while(he<tail)
    {
        he++;
        cur=q[he];
        blb=head[cur];inq[cur]=0;//inq记录点是否在队列里,如果已经在,不用再进入,只更新该点的dis值;he++,对首出对后把 队首的inq记为0;用来下一次入队;
        while(blb!=0)//当前点的边没有全部循环到时
        {
            if(dis[edg[blb].to]>dis[cur]+edg[blb].dis)//可以更新为更短距离
            {
                dis[edg[blb].to]=dis[cur]+edg[blb].dis;//更新
                if(!inq[edg[blb].to])//被更新的点入队用来更新其他点
                {
                    tail++;    q[tail]=edg[blb].to;
                    inq[edg[blb].to]=1;
                
                }
            }
            blb=edg[blb].next;//下一条边
        }
    }
}

int main(){    
    read(n);read(m);
    read(s);
    
    int a,b,c;
    for(int i=1;i<=m;i++)
    {
        read(a);read(b);read(c);
    
        add(a,b,c);
    }
    memset(dis,0x7f,sizeof(dis));
    spfa();
    for(int i=1;i<=n;i++){
        if(dis[i]==2139062143)
        cout<<2147483647<<' ';//没有路
        else
        cout<<dis[i]<<' ';//最短路
    }}

题目来自【模板】单源最短路径(弱化版) - 洛谷

洛谷3371

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值