最短路算法—SPFA算法

SPFA算法 最坏时间复杂度为:\(O(m*n)\).一般为.\(O(m)\)
该算法与堆优化版本的Dijkstra算法很像,但相较与Dijkstra算法每次松弛,SPFA算法仅仅只会松弛更新的最小点与其相关的边。
SPFA算法思想:
每一次松弛可以更新的边,然后将其点加入队列中等待下一次松弛,直到已经松弛完所有的点或者无松弛的边。
下面给出SPFA算法的模板。
SPFA算法的优势:
最佳的求出最短路算法——方便易懂好写
判定是否存在负环——超级源点思想

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;

int n, m;
int h[N], w[N], e[N], ne[N], idx;
int dist[N];
bool st[N];
void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
int spfa()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    
    queue<int> q;
    q.push(1);
    st[1] = true; //st数组存储的是:当前点是否在队列之中;
    /*BFS + 贪心 = SPFA*/
    while(q.size()){
        int t = q.front();
        q.pop();
        st[t] = false;
        
        for(int i = h[t]; i != -1; i = ne[i]){
            int j = e[i];
            if(dist[j] > dist[t] + w[i]){
                dist[j] = dist[t] + w[i];
                if(!st[j]){
                    q.push(j);
                    st[j] = true;
                }
            }
        }
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}
int main()
{
    scanf("%d%d", &n, &m);

    memset(h, -1, sizeof h);
    while (m -- )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c);
    }

  	int ret = spfa();
    printf("%d \n",ret);
    return 0;
}

spfa判断负环,如果存在一个最短路的边长大于等于n的话,说明存在负环
证明:如果不存在负环,对于一个连通图来说,那么一定存在n-1条道路就可以从点\(A\)抵达点\(B\),而现在存在边数为\(n\)的最短路,说明一定存在负环。
此份代码中dist的意为:到dist[i]的最短路为多少。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int h[N],e[N],w[N],ne[N],idx;
bool st[N];
int dist[N];
int cnt[N];
int n,m;

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

bool spfa(){
    queue<int> q;
	for(int i = 1;i <= n;i++){
	    st[i] = true;
	    q.push(i);
	}
	
	while(!q.empty()){
		int t = q.front();
		q.pop();
		st[t] = false;
		
		for(int i = h[t]; i != -1; i = ne[i]){
			int u = e[i];
			if(dist[u] > dist[t] + w[i]){
				dist[u] = dist[t] + w[i];
				cnt[u] = cnt[t] + 1;
				if(cnt[u] >= n) return true;
				if(!st[u]){
					q.push(u);
					st[u] = true;
				}
			}
		}
	} 
	
	return false;
}
int main(){
	scanf("%d%d",&n,&m);
	memset(h , -1, sizeof(h));
	while(m--){
	    int a , b , c;
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c);
	}
	if(spfa()) printf("Yes");
	else printf("No");
	
	return 0;
} 
posted @ 2022-10-15 20:58  Appreciate_小白  阅读(93)  评论(0)    收藏  举报