Bellman_Ford算法 SPFA算法

用spfa 算法求關於有負權邊的最短路。

每次從隊列中取出一個節點X,遍歷與X相通的Y節點,查詢比對  Y的長度X的長度+ X與Y的長度

            如果X的長度+ X與Y的長度 Y的長度,說明需要更新操作。

                    1).存入最短路。

                    2).由於改變了原有的長度,所以需要往後更新,與這個節點相連的最短路。(即:判斷下是否在隊列,在就不用重複,不在就加入隊列,等待更新)。

                    3).在這期間可以記錄這個節點的進隊次數,判斷是否存在負環。

        4.直到隊空。

 

判斷有無負環:如果某個點進入隊列的次數超過N次則存在負環。

給出spfa 模;板

bool spfa(int s){
	queue<int> q;
	for(int i=0;i<=n;i++)
	ksum[i] = vis[i] = 0,dis[i] = INF;
	
	dis[s] = 0,vis[s] = 1,q.push(s);
	while(q.size()){
		int u = q.front();
		q.pop();
		vis[u] = 0; //這裏需要注意,因爲存在負權,spfa每個節點需要重複入隊 
		for(int i = head[u];~i;i = nex[i]){
			int v = to[i],w=edge[i];
			if(dis[u] + w < dis[v]){
				dis[v] = dis[u] + w;
				if(!vis[v]){
					q.push(v); vis[v] = 1;
					if(++ksum[v]> n){
						return true;
					}
				}
			}
		}
	}
	return false;
}

給出模板題:http://poj.org/problem?id=3259

//#include<bits/stdc++.h>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N =3e3;
const int INF = 1e9;
int to[N<<1],nex[N<<1],edge[N<<1];
int n,m,k,cnt;
int dis[N],vis[N],ksum[N],head[N];
void add(int x,int y,int w){
	to[++cnt]= y;
	nex[cnt]= head[x];
	edge[cnt] = w;
	head[x] = cnt;
}
bool spfa(int s){
	queue<int> q;
	for(int i=0;i<=n;i++)
	ksum[i] = vis[i] = 0,dis[i] = INF;
	
	dis[s] = 0,vis[s] = 1,q.push(s);
	while(q.size()){
		int u = q.front();
		q.pop();
		vis[u] = 0;
		for(int i = head[u];~i;i = nex[i]){
			int v = to[i],w=edge[i];
			if(dis[u] + w < dis[v]){
				dis[v] = dis[u] + w;
				if(!vis[v]){
					q.push(v); vis[v] = 1;
					if(++ksum[v]> n){
						return true;
					}
				}
			}
		}
	}
	return false;
}
int main(){
	int t;scanf("%d",&t);
	while(t--){
		cnt = 0;
		memset(head,-1,sizeof head);
		scanf("%d%d%d",&n,&m,&k);
		for(int i = 1,x,y,w;i <= m; i ++){
			scanf("%d%d%d",&x,&y,&w);
			add(x,y,w);
			add(y,x,w);
		}
		for(int i = 1,u,v,w;i <= k; i++){
			scanf("%d%d%d",&u,&v,&w);
			add(u,v,-w);
		}
		if(spfa(1)) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
} 

再給一題簽到題:https://nanti.jisuanke.com/t/41305

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
const int INF = 2e9;
int to[N<<1],nex[N<<1];ll edeg[N<<1];
int n,m,k,cnt;
int head[N];
bool vis[N];
ll dis[N];
void add(int x,int y,int w){
	to[++cnt]= y;
	nex[cnt]= head[x];
	edeg[cnt] = w;
	head[x] = cnt;
}
void spfa(int s){
	queue<int> q;
	for(int i=0;i<=n;i++)
	vis[i] = false,dis[i] = INF;
	
	vis[s]=true,dis[s] = 0,q.push(s);
	while(q.size()){
		int u = q.front();
		q.pop();
		vis[u] = false; //這裏需要注意,因爲存在負權,spfa每個節點需要重複入隊 
		for(int i=head[u];~i;i = nex[i]){
			int v = to[i];
			if(dis[v] > dis[u]+ edeg[i]){
				dis[v] = dis[u] + edeg[i];
				if(!vis[v]){
					q.push(v);
					vis[v] = true;
				}
			}
		}
	}
}
int main(){
	int t;scanf("%d",&t);
	while(t--){
		cnt = 0;
		memset(head,-1,sizeof head);
		scanf("%d%d",&n,&m);
		for(int i = 1,u,v,w;i <= m;i ++){
			scanf("%d%d%d",&u,&v,&w);
			add(u,v,w);
		}
		for(int i=1;i<=6;i++){
			int s,t;scanf("%d%d",&s,&t);
			spfa(t);
			printf("%lld\n",-dis[s]);
			add(s,t,-dis[s]);
		}
	}
	return 0;
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章