SPFA演算法模板(C/C++)

不太聰明的樣子發表於2021-01-03

單源最短路徑演算法,可以用於解決帶負邊權的情況。是佇列優化的Bellman-Ford演算法,時間複雜度O(nm)。

樸素spfa演算法模板

#include <stdio.h>
#include <string.h>

const int N = 1010, M = 2e6, INF = 1e9;

int n, m;	//n是節點數,m是邊數
int dist[N], q[N];	//dist[i]表示源點到i點的最短距離
int h[N], to[M], w[M], ne[M], idx;	//idx初始化為0
bool st[N];	//儲存每個點是否在佇列中

//新增邊表示a到b有一條單向邊,權值為c
void add(int a, int b, int c){
    to[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

//求源點s到其它點的最短路徑
void spfa(int s){
    int hh, tt;	//佇列頭指標和尾指標
    memset(st, false, sizeof(st));
    for(int i = 1; i <= n; i++) dist[i] = INF;
   	dist[s] = 0;
    q[tt++] = s;
    st[s] = true;
    while(hh != tt){	//佇列不為空
        int t = q[hh++];
        st[t] = false;
        if(hh == N) hh = 0;
        for(int i = h[i]; ~i; i = ne[i]){
            if(dist[t] + w[i] < dist[to[i]]){
                dist[to[i]] = dist[t] + w[i];
                if(!st[to[i]]){
                    st[to[i]] = true;
                    q[tt++] = to[i];
                    if(tt == N) tt = 0;
                	}
            	}
        	}
    	}
}

int main(void){
    int a, b, c;
    scanf("%d %d %d", &n, &m, &s);
    memset(h, -1, sizeof(h));
    for(int i = 1; i <= m; i++){
        scanf("%d %d %d", &a, &b, &c);
        add(a, b, c);
    	}
   	spfa(s);
    for(int i = 1; i <= n; i++){
        if(dist[i] == INF) puts("NO PATH");
        else printf("%d\n", dist[i]);
    	}
   	return 0;
}

SLF優化的SPFA演算法

SLF 優化:將普通佇列換成雙端佇列,每次將入隊結點距離和隊首比較,如果更大則插入至隊尾,否則插入隊首

#include <stdio.h>
#include <string.h>
#include <deque>
using namespace std;

const int N = 1010, M = 2e6, INF = 1e9;

int dist[N];
int h[N], to[M], w[M], ne[M], idx;
bool st[N];
int n, m;

void add(int a, int b, int c){
    to[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void spfa(int s){
    memset(st, false, sizeof(st));
    for(int i = 1; i <= n; i++) dist[i] = INF;
    dist[s] = 0;
    deque<int> q;
    q.push_front(s);
    st[s] = true;
    while(!q.empty()){
        int t = q.front();
        q.pop_front();
        st[t] = false;
        for(int i = h[t]; ~i; i = ne[i]){
            if(dist[t] + w[i] < dist[to[i]]){
                dist[to[i]] = dist[t] + w[i];
                if(!st[to[i]]){
                    if(!q.empty() && dist[to[i]] < dist[q.front()]){
                        q.push_front(to[i]);
                    	}
                    else q.push_back(to[i]);
                    st[to[i]] = true;
                	}
            	}
        	}
    	}
}

相關文章