SPFA求最短路——Bellman-Ford算法的优化

SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,一般用于求含负权边的单源最短路径,以及判负权环。SPFA 最坏状况下复杂度和朴素 Bellman-Ford 相同,为 O(VE),可是通常状况下他的复杂度仍是很优秀的,为O(mn),其中稀疏图中m约等于2,稠密图...关于SPFA:他死了,n为边数(值得一提,有的很是bt的数据会故意卡spfa不让你过   好比菊花图,蒲公英图什么的ios

 

算法大意:设立一个队列来保存全部待优化的结点,先初始化全部最短路径,而后从起点开始不断遍历每一条边,不断进行松弛操做,再用已经优化完的结点去更新队列中其余节点算法

 

重要变量解释:优化

dis表示从源点到点i的最短路径
vis表示这个点目前是否在队列里
head表示这个点全部出边中序号最大的那一条spa

 

代码:code

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<time.h>
#include<queue>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pr;
const double pi=acos(-1);
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Rep(i,u) for(int i=head[u];i;i=next[i])
#define clr(a) memset(a,0,sizeof a)
#define pb push_back
#define mp make_pair
#define fi first
#define sc second
ld eps=1e-9;
ll pp=1000000007;
ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
ll read(){
    ll ans=0;
    char last=' ',ch=getchar();
    while(ch<'0' || ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans;
    return ans;
}
//head 

const int inf=2147483647;
int n,m,s;//点的个数、有向边的个数、出发点的编号
int dis[10005],vis[10005],head[10005],cnt;
//dis表示从源点到点i的最短路径
//vis表示这个点目前是否在队列里
//head表示这个点全部出边中序号最大的那一条 

struct Edge
{
    int next,dis,to;
}edge[9999999];

queue <int> q;

inline void add_edge(int from,int to,int dis)
{
    cnt++;
    edge[cnt].next=head[from];
    edge[cnt].to=to;
    edge[cnt].dis=dis;
    head[from]=cnt;
}//存边 

void spfa()
{
    rep(i,1,n)
        dis[i]=inf,vis[i]=0;//初始化 
    dis[s]=0;
    vis[s]=1;//把始点标记成在队列中 
    q.push(s);//入队 
    while(!q.empty())
    {
        int u=q.front();//队首的点 
        q.pop();//出队 
        vis[u]=0;//标记成已经出队 
        for(int i=head[u];i;i=edge[i].next)//遍历每一条边 
        {
            int v=edge[i].to;
            if(dis[v]>dis[u]+edge[i].dis)
            {
                dis[v]=dis[u]+edge[i].dis;//松弛操做 
                if(!vis[v])
                {
                    q.push(v);
                    vis[v]=1;
                }//入队 
            }
        }
    }
}

int main()
{
    scanf("%d %d %d",&n,&m,&s);
    for(int i=1;i<=m;++i)
    {
        int u,v,d;//第i条有向边的出发点、目标点和长度
        scanf("%d %d %d",&u,&v,&d);
        add_edge(u,v,d);
    }
    spfa();
    for(int i=1;i<=n;++i)
    {
        if(i==s) printf("0 ");//本身到本身为0 
        else printf("%d ",dis[i]);
    }
    return 0;
}

 感受和Dijkstra差很少,但其实他俩区别仍是很大的blog

Dijkstra是找到从当前节点全部出边中找到最短的,而后用这条最短边继续更新其余路径队列

而SPFA是对当前节点的全部出边不断进行松弛操做,而后用更新完的边去更新其余结点的其余边ip

其实好像挺像的get

相关文章
相关标签/搜索