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 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
#include
#include
#include
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 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
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 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;
} 

 

你可能感兴趣的:(图论,模板)