差分约束专题

先摘抄一段:

 

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

  求解差分约束系统,可以转化成图论的单源最短路径问题。
  观察xj-xi<=bk,会发现它类似最短路中的三角不等式d[v]<=d[u]+w[u,v],即d[v]-d[u]<=w[u,v]。因此,以每个变量xi为结点,对于约束条件xj-xi<=bk,连接一条边(i,j),边权为bk。我们再增加一个源点s,s与所有定点相连,边权均为0。对这个图,以s为源点运行Bellman-ford算法(或SPFA算法),最终{d[ i]}即为一组可行解。
个人理解,就是根据题目给出的限定关系,得到一组方程组, 统一方程不等号(必须是>= 或者是<=)的方向。根据三角不等式构建出边来,利用spfa求解。求最小值用最长路,求最大值用最短路。
 
poj 1275 Cashier Employment 难度***
题意:一家24小时营业的超市要雇用职员,每个时段需要的职员数量为R(i);每个员工会不间断的工作8小时,现有N个求职者,已知求职者的工作开始时间,问至少要雇用多少职员才能满足超市需求。
解析:黑书上有这道题目。我们设s[i]表示0~i时刻雇用的出纳员总数,r[i]表示每小时要的出纳员数目,t[i]表示每小时申请者的数目。因为由s的定义可知:0<=s[i]-s[i-1]<=t[i]。设s[-1]=0,s[23]-s[-1]>=需要的人数;由于有每小时最低人数的限制,所以s[i]-s[i-8]>=r[i]。综上可有:
s[i]-s[i-1]>=0
s[i-1]-s[i]>=-t[i]
s[23]-s[-1]>=sum
s[ i ]-s[ j ]=r[i] (i>j ,i=(j+8-1)%24+1)
s[ i ]-s[ j ]=r[i]-sum (i<j, i=(j+8-1)%24+1)
二分需要的人数sum,根据以上条件构边,求最长路,判断是否存在正环,是否存在解。
 
poj 1201Intervals 难度***
题意:给定N个区间以及每个区间的Ci,求一个大小最小的整数集合,使该集合落在每个区间上的元素个数大于等于区间的Ci,输出该集合大小。
解析:我们用d[i]来表示集合中从开头到位置i的元素个数。则由d[i]的定义有:0<=d[i]-d[i-1]<=1,d[vi+1]>=d[ui]+Ci;根据以上关系建边求最长路即可。
 
poj 1716 Integer Intervals 难度**
题意:跟1201一样,是1201的简化版,要求集合落在每个区间上的元素个数大于等于2.
解析:把1201的边的w改为2即可。。。。。
 
poj 1364 King 难度**
题意:一个可怜的王二代继承王位了,他只会比较一段连续数字的和与某数字的大小,上位不久就有一批大臣想推翻他,王二代必须证明自己,于是他指出一段连续数字里面某一区间的和大于或小于某个数,你是王二代的谋臣,请为他鉴定是否存在这样的一段连续数字。
解析:理解了题意就很好办了,设su[i]表示第0个到第i这几个数字的和,则如果a~b这段区间的和为sum[a]-sum[b-1]。如果a~b的和大于c则sum[a]-sum[b-1]>c由于差分约束里的三角不等式用的是>=或<=且c恰好是整数,所以有sum[a]-sum[b-1]>=c+1小于的情况也同理。建好边后求负环即可。
代码:
	#include<iostream>
#include <cstdio>
using namespace std;

struct Edge
{
	int u,v,w;
}e[101];

int sum[101];
int M,N;

bool BellmanFord()
{
	for(int i=0;i<=N;i++)
		sum[i]=0;
	for(int k=0;k<N;k++)
		for(int i=0;i<M;i++)
			if(sum[e[i].u]+e[i].w<sum[e[i].v])
				sum[e[i].v]=sum[e[i].u]+e[i].w;
	for(int i=0;i<M;i++)
		if(sum[e[i].u]+e[i].w<sum[e[i].v])
			return false;
	return true;
}

int main()
{
	while(scanf("%d",&N),N)
	{
		scanf("%d",&M);
		char op[3];
		int si,ni,ki;
		for(int i=0;i<M;i++)
		{
			scanf("%d%d%s%d",&si,∋,op,&ki);
			if(op[0]=='g')
			{
				e[i].u=si+ni;
				e[i].v=si-1;
				e[i].w=-ki-1;
			}
			else
			{
				e[i].u=si-1;
				e[i].v=si+ni;
				e[i].w=ki-1;
			}
		}
		if(!BellmanFord())
			printf("successful conspiracy\n");
		else
			printf("lamentable kingdom\n");
	}
	return 0;
}

 

poj 3169 Layout难度*

题意:农夫FJ的牛排成一行等着吃饭,有些牛相互讨厌,他们之间距离的至少大于di,有些牛相互暧昧,他们之间的距离最多小于li问满足条件的队伍的最长距离。

解析:应该是比较水的一个题了(第一次做多校一个类似的题时居然没看出来)。求最大值,用最短路。如果A与B相互讨厌,他们之间的距离应大于di,则有dis[B]-dis[A]>=di,建一条<B,A,-di>的边。暧昧时同理。spfa求最短路时出现负环说明无解,dis[N]=INF则说明牛的位置可以是任意的(因为没有限制条件传递到N,所以N的值是初始的值,即N的位置不受限制),否则输出dis[N]。(其实应该添加dis[i]>=dis[i-1]的,但没加也过了)

 

poj 2983 Is the Information Reliable?难度**

题意:跟上面一题是一样的,这题有两种输入:P A B X表示A到B的距离正好等于X,V A B表示A的距离至少比B大1。问满足条件的解是否存在。

解析:对于P A B X,即dis[A]-dis[B]=X可以转化为:X<=dis[A]-dis[B]<=X ,据此构出两条边。对于V A B 即dis[A]-dis[B]>=1,再构造出边。这题要小心了,很多人用BellmanFord过用SPFA Wa了,要注意有些点是孤立点,或者一些集合构成孤立的集合,所以我们要建一个超级源点,连到所有的点,边的w=0 。最后判负环即可。

 

zoj 1455 Schedule Problem难度***

题意:一个工程分为N个部分,给出每个部分持续时间,以及几对部分之间的关系:FAS, FAF, SAF and SAS.输出每个部分的起始时间。

解析:约束关系比较明朗,以t[i]表示部分i什么时候开始d[i]表示部分i的持续时间,则有:

FAS:  t[a]>=t[b]+d[a]

FAF: t[a]>=t[b]+d[b]-d[a]

SAS: t[a]>=t[b]

SAF: t[a]>=t[b]+d[b]

求最长路,设一个超级源点到所有点的权值为0.最后输出t[i]即可。