P4878 [USACO05DEC]Layout G 差分约束

题目大意

  • 和人类一样,奶牛们在打饭的时候喜欢和朋友站得很近。
  • 约翰的编号为 1 到 n 的 n(2<=n<=1000) 只奶牛正打算排队打饭。现在请你来安排她们,让她们在数轴上排好队。奶牛的弹性很好,同一个坐标可以站无限只奶牛,排队的顺序必须和她们编号的顺序一致。
  • 有 M 对奶牛互相爱慕,她们之间的距离不能超过一定的值,有 K 对奶牛互相敌视,她们的距离不能小于一定的值。那么,首尾奶牛的最大距离是多少呢?

输入格式

  • 第一行输入 n,M,K,(0<M,K<=5000)。
  • 接下来 M 行每行三个整数x,y,z,表示编号为 x 和 y 的两头奶牛之间的距离最大不超过 z。
  • 再接下来 K 行每行三个整数 a,b,c,表示编号为 a 和 b 的两头奶牛之间的距离最少为c。

输出格式

  • 如果没有合理方案,输出 −1,如果首尾两头牛的距离可以无限大,输出 −2,否则输出一个整数表示首尾奶牛的最大距离。

样例输入

4 2 1
1 3 10
2 4 20
2 3 3

样例输出

27

算法分析

  • 不会吧不会吧不会真的有人看不出来这是差分约束吧
  • 然后就是一个差分约束的板子题了
  • 建边跑最短路(求最大值)
  • 建超级源点

算法展示

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3+10,maxm = 2e4+10;
const int Inf = 0x3f3f3f3f;
int n;
int head[maxn],cnt;
int num[maxn],dis[maxn],vis[maxn];

struct node{
	int next,to,dis;
}a[maxm];

void add(int x,int y,int z){
	a[++cnt].to = y;
	a[cnt].next = head[x];
	a[cnt].dis = z;
	head[x] = cnt;
}

queue<int> q;

int spfa(int u){
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	memset(num,0,sizeof(num));
	q.push(u);vis[u] = 1;
	dis[u] = 0;
	while(!q.empty()){
		int u = q.front();q.pop();vis[u] = 0;
		for(int i = head[u];i;i = a[i].next){
			int v = a[i].to;
			if(dis[v] > dis[u] + a[i].dis){
				dis[v] = dis[u] + a[i].dis;
				if(!vis[v]){
					vis[v] = 1;q.push(v);
					num[v]++;
					if(num[v] > n)return -1;//判负环
				}
			}
		}
	}
	if(dis[n] == Inf)return -2;//如果无限大
	return dis[n];
}

int main(){
	int m,k;scanf("%d%d%d",&n,&m,&k);
	for(int i = 1;i <= m;++i){
		int x,y,z;scanf("%d%d%d",&x,&y,&z);
		if(x > y)swap(x,y);
		add(x,y,z);
	}
	for(int i = 1;i <= k;++i){
		int x,y,z;scanf("%d%d%d",&x,&y,&z);
		if(x > y)swap(x,y);
		add(y,x,-z);//建边
	}
	for(int i = 1;i < n;++i)add(i+1,i,0);//建边 
	for(int i = 1;i <= n;++i)add(0,i,0);//超级源点
	if(spfa(0) == -1){printf("-1
");return 0;}//超级源点为起点跑spfa 防止有的负环无法到达的情况
	printf("%d
",spfa(1));
	return 0;
}

谢谢观看>:<

如初见 与初见
原文地址:https://www.cnblogs.com/HISKrrr/p/13324828.html