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

相關文章
相關標籤/搜索