洛谷 P5960 【模板】差分约束算法(spfa)

传送门


解题思路

给你(n)个不等式,(ai<=aj+k)
像极了最短路中松弛的式子
所以做法就出来了:
对于每一个是上面形式的式子,我们从(j)(i)连一条长度为(k)的边,这样我们保证了到(i)的最短路一定(<=)(j)的最短路。
建立一个超级源点,连向每一个点,边权为(0),求一遍最短路spfa,每个点到超级源点的最短路长度即为值的大小,而刚刚边权(0)其实就是确定了最终解的上界大小,即解都(<=0)
注意有负环则无解(用spfa可判断)。

AC代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=5005;
int n,m,p[maxn],dis[maxn],cnt,vis[maxn],times[maxn];
struct node{
	int v,next,w;
}e[maxn*2];
void insert(int u,int v,int w){
	cnt++;
	e[cnt].v=v;
	e[cnt].w=w;
	e[cnt].next=p[u];
	p[u]=cnt;
}
queue<int> q;
bool spfa(){
	memset(dis,0x3f,sizeof(dis));
	dis[0]=0;
	q.push(0);
	vis[0]=1;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		times[u]++;
		if(times[u]>n) return false;
		for(int i=p[u];i!=-1;i=e[i].next){
			int v=e[i].v;
			if(dis[v]>dis[u]+e[i].w){
				dis[v]=dis[u]+e[i].w;
				if(!vis[v]){
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	return true;
}
int main()
{
	memset(p,-1,sizeof(p));
    cin>>n>>m;
    for(int i=1;i<=m;i++){
    	int u,v,w;
    	scanf("%d%d%d",&v,&u,&w);
    	insert(u,v,w);
	}
	for(int i=1;i<=n;i++) insert(0,i,0);
	if(!spfa()){
		cout<<"NO"<<endl;
		return 0;
	}
	for(int i=1;i<=n;i++) cout<<dis[i]<<' ';
    return 0;
}
原文地址:https://www.cnblogs.com/yinyuqin/p/14783402.html