洛谷P1260 工程规划

题目链接

https://www.luogu.com.cn/problem/P1260

思路

这是一道差分约束模板题。什么是差分约束?简单来说就是一组\(n\)元一次不等式组,每个不等式以\(x_i-x_j\leq k\)的形式给出,求化简之后各个变量之间的关系。

可以看成图论问题,如果\(x_i-x_j\leq k\),我们就建一条从\(x_j\)\(x_i\)(注意顺序!!),边权为\(k\)的边,表示\(x_j\)\(x_i\)的距离\(\leq k\)

钦定一个源点,那么对任意\(x_i\)\(x_i\)需要满足从源点到\(x_i\)的路径代表的所有不等式,所以\(x_i\)的最大值就是源点到\(x_i\)的最短路(各个解集求交集,\(x_i\leq\)最短路)。

比如:\(\left\{\begin{array}\\x_5-x_1\leq -1\\{x_2-x_1<=0}\\x_5-x_2\leq 1 \end{array}\right.\)
联立解得\(x_5-x_1\leq -1\),就是\(x_1\)\(x_5\)的最短路。

注意有负权边,如果有负环的话该不等式组无解(相当于套圈之后\(x_i\leq x_i-C\)(C是某常数)),体现在spfa中就是某节点入队次数大于总点数。

但是这是针对连通图而言,如果图不连通,有的节点根本无法访问到,那就建一个超级源S,加入S到1至n号节点的n条边,边权为0。

代码

#include<cstdio>
#include<cstdlib>
#include<queue>
#define db double
#define inf 0x3f3f3f3f
#define maxn (int)(1e4+10)
using namespace std;
int fst[maxn],nxt[maxn],w[maxn],to[maxn],cnt=0,dis[maxn],n,m;
int book[maxn],flag=0,num[maxn];
void add(int x,int y,int z){
	w[++cnt]=z;
	to[cnt]=y;
	nxt[cnt]=fst[x];
	fst[x]=cnt;
}
bool spfa(){
	int i;
	queue<int> q;
	while(!q.empty()) q.pop();
	for(i=1;i<=n;++i)
		dis[i]=inf;
	q.push(n+1);
	book[n+1]=1;
	while(!q.empty()){
		int p=q.front();
		for(i=fst[p];i;i=nxt[i]){
			if(dis[p]+w[i]<dis[to[i]]){
				dis[to[i]]=dis[p]+w[i];
				if(!book[to[i]]){
					num[to[i]]++;
					if(num[to[i]]>n+1) return 0;
					q.push(to[i]);
					book[to[i]]=1;
				}
			}
		}
		book[p]=0;
		q.pop();
	}
	return 1;
}
int main(){
	int i,x,y,z,MIN=inf;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;++i){
		scanf("%d%d%d",&x,&y,&z);
		add(y,x,z);
	}
	for(i=1;i<=n;i++){
		add(n+1,i,0);
	}
	if(spfa()){
		for(i=1;i<=n;i++)
			MIN=min(MIN,dis[i]);
		for(i=1;i<=n;i++)
			printf("%d\n",dis[i]-MIN);
	}
	else printf("NO SOLUTION");
	// system("pause");
	return 0;
}
posted @ 2020-11-12 12:37  文艺平衡树  阅读(114)  评论(0编辑  收藏  举报