1. 程式人生 > 實用技巧 >最短路SPFA

最短路SPFA

SPFA演算法是對Bellman-ford演算法的優化,

優化的思想:Bellman-ford演算法是遍歷所有邊,對邊進行鬆弛操作,但是如果前一個邊的距離沒有變化,那麼後一個邊的距離也不會變化。通過這個特性,我們可以將變化距離的點存在佇列中,只對這些點的後繼點進行鬆弛操作。

SPFA演算法的時間複雜度為O(m)-O(nm),m為邊數,n為點數,最壞情況與Bellman-ford演算法相同。

acwing851. spfa求最短路

給定一個n個點m條邊的有向圖,圖中可能存在重邊和自環, 邊權可能為負數

請你求出1號點到n號點的最短距離,如果無法從1號點走到n號點,則輸出impossible。

資料保證不存在負權迴路。

輸入格式:

第一行包含整數n和m。

接下來m行每行包含三個整數x,y,z,表示存在一條從點x到點y的有向邊,邊長為z。

輸出格式:

輸出一個整數,表示1號點到n號點的最短距離。

如果路徑不存在,則輸出”impossible”。

資料範圍:

1n,m1e5

圖中涉及邊長絕對值均不超過10000。

輸入樣例:

3 3
1 2 5
2 3 -3
1 3 4

輸出樣例:

2

模板程式碼:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace
std; typedef pair<int,int>pii; const int N=1e5+10; int n,m; int d[N]; int f[N]; vector<pii>v[N]; int spfa() { memset(d,0x3f,sizeof d); d[1]=0; queue<int>q; q.push(1); f[1]=1; while(!q.empty()) { int t=q.front(); q.pop(); f[t]=0;
for(int i=0;i<v[t].size();i++) { pii y=v[t][i]; if(d[y.first]>y.second+d[t]) { d[y.first]=y.second+d[t]; if(!f[y.first]) { f[y.first]=1; q.push(y.first); } } } } if(d[n]>0x3f3f3f3f/2) return -1;//存在負權邊 return d[n]; } int main() { scanf("%d%d",&n,&m); for(int i=0;i<m;i++) { int x,y,w; scanf("%d%d%d",&x,&y,&w); v[x].push_back({y,w}); } int k=spfa(); if(k==-1) printf("impossible\n"); else printf("%d\n",k); return 0; }

acwing852. spfa判斷負環

給定一個n個點m條邊的有向圖,圖中可能存在重邊和自環, 邊權可能為負數

請你判斷圖中是否存在負權迴路。

輸入格式

第一行包含整數n和m。

接下來m行每行包含三個整數x,y,z,表示存在一條從點x到點y的有向邊,邊長為z。

輸出格式

如果圖中存在負權迴路,則輸出“Yes”,否則輸出“No”。

資料範圍

1n2000

1≤m≤10000,
圖中涉及邊長絕對值均不超過10000。

輸入樣例:

3 3
1 2 -1
2 3 4
3 1 -4

輸出樣例:

Yes

分析:引入cnt陣列,記錄每個點到點1所需要的邊數,當某個點的cnt邊數大於等於n時,說明,在求1到這個點的路徑上出現了負環。

程式碼:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int M=1e4+10,N=2e3+10;
typedef pair<int,int>pii;
int n,m;
vector<pii>v[N];
int d[N];
bool f[N];
int cnt[N];
int spfa()
{
    queue<int>q;
    for(int i=1;i<=n;i++)
    {
        d[i]=0x3f3f3f3f;
        f[i]=1;
        q.push(i);
    }
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        f[t]=0;
        for(int i=0;i<v[t].size();i++)
        {
            pii y=v[t][i];
            if(d[y.first]>y.second+d[t])
            {
                d[y.first]=y.second+d[t];
                cnt[y.first]=cnt[t]+1;
                if(cnt[y.first]>=n) return true;
                if(!f[y.second])
                {
                    q.push(y.first);
                    f[y.first]=1;
                }
            }
        }
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
    {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        v[x].push_back({y,w});
    }
    int k=spfa();
    if(k) printf("Yes\n");
    else printf("No\n");
    return 0;
}