POJ3169 差分约束

题目:

Layout
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 13445 Accepted: 6447

Description

Like everyone else, cows like to stand close to their friends when queuing for feed. FJ has N (2 <= N <= 1,000) cows numbered 1..N standing along a straight line waiting for feed. The cows are standing in the same order as they are numbered, and since they can be rather pushy, it is possible that two or more cows can line up at exactly the same location (that is, if we think of each cow as being located at some coordinate on a number line, then it is possible for two or more cows to share the same coordinate). 

Some cows like each other and want to be within a certain distance of each other in line. Some really dislike each other and want to be separated by at least a certain distance. A list of ML (1 <= ML <= 10,000) constraints describes which cows like each other and the maximum distance by which they may be separated; a subsequent list of MD constraints (1 <= MD <= 10,000) tells which cows dislike each other and the minimum distance by which they must be separated. 

Your job is to compute, if possible, the maximum possible distance between cow 1 and cow N that satisfies the distance constraints.

Input

Line 1: Three space-separated integers: N, ML, and MD. 

Lines 2..ML+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at most D (1 <= D <= 1,000,000) apart. 

Lines ML+2..ML+MD+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at least D (1 <= D <= 1,000,000) apart.

Output

Line 1: A single integer. If no line-up is possible, output -1. If cows 1 and N can be arbitrarily far apart, output -2. Otherwise output the greatest possible distance between cows 1 and N.

Sample Input

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

Sample Output

27

题意:

n头牛编号1~n。按照编号顺序排成一排。有ML对关系好的牛的信息,(AL,BL,DL)。有MD对关系差的牛的信息,(AD,BD,DD)。要求牛AL与牛BL之间的最大距离为DL,牛AD与牛BD之间的最大距离为DD。在满足这些条件的方法中,求1号牛与n号牛的最大距离。不存在输出-1,无限大输出-2。

方法:差分约束(摘自点击打开链接

一、何为差分约束系统:

差分约束系统(system of difference constraints),是求解关于一组变数的特殊不等式组之方法。如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如xj-xi<=bk(i,j∈[1,n],k∈[1,m]),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。

通俗一点地说,差分约束系统就是一些不等式的组,而我们的目标是通过给定的约束不等式组求出最大值或者最小值或者差分约束系统是否有解。

比如:


二、差分约束系统的求解:

差分约束系统可以转化为图论来解决,对应于上面的不等式组,如果要求出x3-x0的最大值的话,叠加不等式可以推导出x3-x0<=7,最大值即为7,我们可以通过建立一个图,包含6个顶点,对每个xj-xi<=bk,建立一条i到j的有向边,权值为bk。通过求出这个图的x0到x3的最短路可以知道也为7,这是巧合吗?并不是。

之所以差分约束系统可以通过图论的最短路来解,是因为xj-xi<=bk,会发现它类似最短路中的三角不等式d[v] <=d[u]+w[u,v],即d[v]-d[u]<=w[u,v]。而求取最大值的过程类似于最短路算法中的松弛过程。

三角不等式:(在此引用大牛的博客)

B - A <= c     (1)

C - B <= a     (2)

C - A <= b     (3)

 如果要求C-A的最大值,可以知道max(C-A)= min(b,a+c),而这正对应了下图中C到A的最短路。 

                                

因此,对三角不等式加以推广,变量n个,不等式m个,要求xn-x1的最大值,便就是求取建图后的最短路。

同样地,如果要求取差分约束系统中xn-x1的最小值,便是求取建图后的最长路。最长路可以通过spfa求出来,只需要改下松弛的方向即可,即if(d[v] < d[u] + dist(u,v)) d[v] = d[u] + dist(u,v)。当然我们可以把图中所有的边权取负,求取最短路,两者是等价的。

最长路求解算法证明如下:

http://www.cnblogs.com/g0feng/archive/2012/09/13/2683880.html

最后一点,建图后不一定存在最短路/最长路,因为可能存在无限减小/增大的负环/正环,题目一般会对应于不同的输出。判断差分约束系统是否存在解一般判环即可。


3、差分约束系统的应用

差分约束系统的应用很广,都会有一定的背景,我们只需要根据题意构造出差分约束系统,然后再根据题目的要求求解就行了。

一般题目会有三种情况:(1)、求取最短路 (2)、求取最长路 (3)、判断差分约束系统的解是否存在

当然这三种也可能会相互结合。

 

差分约束系统的解法如下:

1、  根据条件把题意通过变量组表达出来得到不等式组,注意要发掘出隐含的不等式,比如说前后两个变量之间隐含的不等式关系。

2、  进行建图:

首先根据题目的要求进行不等式组的标准化。

(1)、如果要求取最小值,那么求出最长路,那么将不等式全部化成xi – xj >= k的形式,这样建立j->i的边,权值为k的边,如果不等式组中有xi – xj > k,因为一般题目都是对整形变量的约束,化为xi – xj >= k+1即可,如果xi – xj = k呢,那么可以变为如下两个:xi – xj >= k, xi – xj <= k,进一步变为xj – xi >= -k,建立两条边即可。

(2)、如果求取的是最大值,那么求取最短路,将不等式全部化成xi – xj <= k的形式, 这样建立j->i的边,权值为k的边,如果像上面的两种情况,那么同样地标准化就行了。

(3)、如果要判断差分约束系统是否存在解,一般都是判断环,选择求最短路或者最长路求解都行,只是不等式标准化时候不同,判环地话,用spfa即可,n个点中如果同一个点入队超过n次,那么即存在环。

值得注意的一点是:建立的图可能不联通,我们只需要加入一个超级源点,比如说求取最长路时图不联通的话,我们只需要加入一个点S,对其他的每个点建立一条权值为0的边图就联通了,然后从S点开始进行spfa判环。最短路类似。

3、  建好图之后直接spfa或bellman-ford求解,不能用dijstra算法,因为一般存在负边,注意初始化的问题。


本题中存在3种约束:第一种为牛的排列:d[i]<=d[i+1] ; 

第二种为关系好的牛所限制的最大距离:d[AL] + DL >=d[BL];

第三种为关系差的牛限制的最小距离:d[AD] + DD <=d[BD]。

题目中求1号牛到n号牛的最大值,即求1到n的最短路。

变型不等式为最短路松弛形式操作得:d[i+1]+0 >= d[i] ,  d[AL]+DL >=d[BL] ,  d[BD]-DD >= d[AD]。

然后根据所有不等式建图,跑SPFA即可。

若SPFA过程中判出负环,则无解。

若结果最短路d[n] 为INF,则无约束,1到n的距离可以无限大。

代码:

#include<cstdio>  
#include<cstdlib>  
#include<cmath>  
#include<cstring>  
#include<iostream>  
#include<algorithm>  
#include<queue>  
#include<map>  
#include<stack> 
#define sd(x) scanf("%d",&x)
#define ss(x) scanf("%s",x)
#define sc(x) scanf("%c",&x)
#define sf(x) scanf("%f",&x)
#define slf(x) scanf("%lf",&x)
#define slld(x) scanf("%lld",&x)
#define me(x,b) memset(x,b,sizeof(x))
#define pd(d) printf("%d\n",d);
#define plld(d) printf("%lld\n",d);
// #define Reast1nPeace

typedef long long ll;

using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 10010;

int n,ml,md;
int k;
struct edge{
	int to,weight,next;
}G[maxn*2];

int head[maxn];

int d[maxn];
bool vis[maxn];
int num[maxn];

void spfa(){
	queue<int> q;
	memset(d,INF,sizeof(d));
	memset(num,0,sizeof(num));
	memset(vis,0,sizeof(vis));
	
	q.push(1);
	vis[1] = 1;
	d[1] = 0;
	num[1]++; 
	while(!q.empty()){
		int now = q.front(); q.pop();
		
		for(int i = head[now] ; i!=0 ; i = G[i].next){
			if(d[now] + G[i].weight < d[G[i].to] ){
				d[G[i].to] = d[now]+G[i].weight;
				if(!vis[G[i].to]){
					q.push(G[i].to);
					vis[G[i].to] = 1;
					num[G[i].to]++;
					
					if(num[G[i].to] >= n){
						cout<<"-1"<<endl;
						return;
					} 
				}
			}
		}
		vis[now] = 0;
	}
	if(d[n] == INF){
		cout<<-2<<endl;
		return;
	}
	cout<<d[n]<<endl;
}

int main(){
#ifdef Reast1nPeace
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif
	ios::sync_with_stdio(false);
	memset(head,0,sizeof(head));
	memset(G,0,sizeof(G));
	
	cin>>n>>ml>>md;
	
	int a,b,d;
	k = 1;
	
	for(int i = 2 ; i<=n ; i++){
		G[k].to = i-1;
		G[k].weight = 0;
		G[k].next = head[i];
		head[i] = k;
		k++;
	}
	
	for(int i = 1 ; i<=ml ; i++){
		cin>>a>>b>>d;
		G[k].to = b;
		G[k].weight = d;
		G[k].next = head[a];
		head[a] = k;
		k++;
	}
	
	for(int i = 1 ; i<=md ; i++){
		cin>>a>>b>>d;
		G[k].to = a;
		G[k].weight = -d;
		G[k].next = head[b];
		head[b] = k;
		k++;
	}
	
	spfa();
	
	return 0;
}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值