差分约束初学整合

来源:互联网 发布:c语言全屏玫瑰花代码 编辑:程序博客网 时间:2024/06/05 14:19

首先说明,此篇博客是我在初学差分约束时将看到过的所有很好很经典博客里简单易懂或者精彩的部分摘取组合而成的。每一篇博客侧重点不同,有些讲的比较粗略但是另一些博客很详细,所以我觉得将这些精华聚合在一起还是很重要的,每篇博客我都会标明出处。另外有些地方我也会增加一些我自己的见解,如果有不对的地方,希望各位大佬指出。如果您觉得好的话欢迎转载,但请说明出处:http://blog.csdn.NET/qq_34374664/article/details/52787481
转自:http://www.cppblog.com/menjitianya/archive/2015/11/19/212292.html
目录  

一、引例
      1、一类不等式组的解

二、最短路
      1、Dijkstra
      2、图的存储
      3、链式前向星
      4、Dijkstra + 优先队列
      5、Bellman-Ford
      6、SPFA
      7、Floyd-Warshall

三、差分约束
       1、数形结合
       2、三角不等式
       3、解的存在性
       4、最大值 => 最小值
       5、不等式标准化

四、差分约束的经典应用
       1、线性约束
       2、区间约束
       3、未知条件约束
         
五、差分约束题集整理

一、引例
       1、一类不等式组的解
      给定n个变量和m个不等式,每个不等式形如 x[i] - x[j] <= a[k] (0 <= i, j < n, 0 <= k < m, a[k]已知),求 x[n-1] - x[0] 的最大值。例如当n = 4,m = 5,不等式组如图一-1-1所示的情况,求x3 - x0的最大值。
图一-1-1
      观察x3 - x0的性质,我们如果可以通过不等式的两两加和得到c个形如 x3 - x0 <= Ti 的不等式,那么 min{ Ti | 0 <= i < c } 就是我们要求的x3 - x0的最大值。于是开始人肉,费尽千辛万苦,终于整理出以下三个不等式:
      1.      (3)                       x3 - x0 <= 8
      2.      (2) + (5)              x3 - x0 <= 9
      3.      (1) + (4) + (5)     x3 - x0 <= 7
      这里的T等于{8, 9, 7},所以min{ T } = 7,答案就是7。的确是7吗?我们再仔细看看,发现的确没有其它情况了。那么问题就是这种方法即使做出来了还是带有问号的,不能确定正确与否,如何系统地解决这类问题呢?
      让我们来看另一个问题,这个问题描述相对简单,给定四个小岛以及小岛之间的有向距离,问从第0个岛到第3个岛的最短距离。如图一-1-2所示,箭头指向的线段代表两个小岛之间的有向边,蓝色数字代表距离权值。

图一-1-2
      这个问题就是经典的最短路问题。由于这个图比较简单,我们可以枚举所有的路线,发现总共三条路线,如下:
      1.       0 -> 3                       长度为8
      2.       0 -> 2 -> 3               长度为7+2 = 9
      3.       0 -> 1 -> 2 -> 3       长度为2 + 3 + 2 = 7
      最短路为三条线路中的长度的最小值即7,所以最短路的长度就是7。这和上面的不等式有什么关系呢?还是先来看看最短路求解的原理,看懂原理自然就能想到两者的联系了。


三、差分约束
      1、数形结合
      介绍完最短路,回到之前提到的那个不等式组的问题上来,我们将它更加系统化。
      如若一个系统由n个变量和m个不等式组成,并且这m个不等式对应的系数矩阵中每一行有且仅有一个1和-1,其它的都为0,这样的系统称为差分约束( difference constraints )系统。引例中的不等式组可以表示成如图三-1-1的系数矩阵。
图三-1-1
      然后继续回到单个不等式上来,观察 x[i] - x[j] <= a[k], 将这个不等式稍稍变形,将x[j]移到不等式右边,则有x[i] <= x[j] + a[k],然后我们令a[k] = w(j, i),再将不等式中的i和j变量替换掉,i = v, j = u,将x数组的名字改成d(以上都是等价变换,不会改变原有不等式的性质),则原先的不等式变成了以下形式:d[u] + w(u, v) >= d[v]。
      这时候联想到SPFA中的一个松弛操作:
    if(d[u] + w(u, v) < d[v]) {
        d[v] = d[u] + w(u, v);
    }
      对比上面的不等式,两个不等式的不等号正好相反,但是再仔细一想,其实它们的逻辑是一致的,因为SPFA的松弛操作是在满足小于的情况下进行松弛,力求达到d[u] + w(u, v) >= d[v],而我们之前令a[k] = w(j, i),所以我们可以将每个不等式转化成图上的有向边:
      对于每个不等式 x[i] - x[j] <= a[k],对结点 j 和 i 建立一条 j -> i的有向边,边权为a[k],求x[n-1] - x[0] 的最大值就是求 0 到n-1的最短路。
图三-1-2
      图三-1-2 展示了 图三-1-1的不等式组转化后的图。

      2、三角不等式
      如果还没有完全理解,我们可以先来看一个简单的情况,如下三个不等式:
B - A <= c      (1)
C - B <= a      (2)
C - A <= b      (3)
      我们想要知道C - A的最大值,通过(1) + (2),可以得到 C - A <= a + c,所以这个问题其实就是求min{b, a+c}。将上面的三个不等式按照 三-1 数形结合 中提到的方式建图,如图三-2-1所示。
图三-2-1
      我们发现min{b, a+c}正好对应了A到C的最短路,而这三个不等式就是著名的三角不等式。将三个不等式推广到m个,变量推广到n个,就变成了n个点m条边的最短路问题了。

      3、解的存在性
      上文提到最短路的时候,会出现负权圈或者根本就不可达的情况,所以在不等式组转化的图上也有可能出现上述情况,先来看负权圈的情况,如图三-3-1,下图为5个变量5个不等式转化后的图,需要求得是X[t] - X[s]的最大值,可以转化成求s到t的最短路,但是路径中出现负权圈,则表示最短路无限小,即不存在最短路,那么在不等式上的表现即X[t] - X[s] <= T中的T无限小,得出的结论就是 X[t] - X[s]的最大值 不存在。
图三-3-1
      再来看另一种情况,即从起点s无法到达t的情况,如图三-3-2,表明X[t]和X[s]之间并没有约束关系,这种情况下X[t] - X[s]的最大值是无限大,这就表明了X[t]和X[s]的取值有无限多种
图三-3-2
      在实际问题中这两种情况会让你给出不同的输出。综上所述,差分约束系统的解有三种情况:1、有解;2、无解;3、无限多解

      4、最大值 => 最小值
      然后,我们将问题进行一个简单的转化,将原先的"<="变成">=",转化后的不等式如下:
B - A >= c      (1)
C - B >= a      (2)
C - A >= b      (3)
      然后求C - A的最小值,类比之前的方法,需要求的其实是max{b, c+a},于是对应的是图三-2-1从A到C的最长路。同样可以推广到n个变量m个不等式的情况。
      
      5、不等式标准化
      如果给出的不等式有"<="也有">=",又该如何解决呢?很明显,首先需要关注最后的问题是什么,如果需要求的是两个变量差的最大值,那么需要将所有不等式转变成"<="的形式,建图后求最短路;相反,如果需要求的是两个变量差的最小值,那么需要将所有不等式转化成">=",建图后求最长路。
      如果有形如:A - B = c 这样的等式呢?我们可以将它转化成以下两个不等式:
A - B >= c      (1)
A - B <= c      (2)
       再通过上面的方法将其中一种不等号反向,建图即可。
       最后,如果这些变量都是整数域上的,那么遇到A - B < c这样的不带等号的不等式,我们需要将它转化成"<="或者">="的形式,即 A - B <= c - 1。
四、差分约束的经典应用
      1、线性约束
        线性约束一般是在一维空间中给出一些变量(一般定义位置),然后告诉你某两个变量的约束关系,求两个变量a和b的差值的最大值或最小值。
     【例题1】N个人编号为1-N,并且按照编号顺序排成一条直线,任何两个人的位置不重合,然后给定一些约束条件。
       X(X <= 100000)组约束Ax Bx Cx(1 <= Ax < Bx <= N),表示Ax和Bx的距离不能大于Cx。
       Y(X <= 100000)组约束Ay By Cy(1 <= Ay < By <= N),表示Ay和By的距离不能小于Cy。
       如果这样的排列存在,输出1-N这两个人的最长可能距离,如果不存在,输出-1,如果无限长输出-2。
      像这类问题,N个人的位置在一条直线上呈线性排列,某两个人的位置满足某些约束条件,最后要求第一个人和最后一个人的最长可能距离,这种是最直白的差分约束问题,因为可以用距离作为变量列出不等式组,然后再转化成图求最短路。
      令第x个人的位置为d[x](不妨设d[x]为x的递增函数,即随着x的增大,d[x]的位置朝着x正方向延伸)。
      那么我们可以列出一些约束条件如下:
      1、对于所有的Ax Bx Cx,有 d[Bx] - d[Ax] <= Cx;
      2、对于所有的Ay By Cy,有 d[By] - d[Ay] >= Cy;
      3、然后根据我们的设定,有 d[x] >= d[x-1] + 1 (1 < x <= N)  (这个条件是表示任何两个人的位置不重合)
     而我们需要求的是d[N] - d[1]的最大值,即表示成d[N] - d[1] <= T,要求的就是这个T。
     于是我们将所有的不等式都转化成d[x] - d[y] <= z的形式,如下:
      1、d[Bx]  -  d[Ax]    <=    Cx
      2、d[Ay]  -  d[By]    <=  -Cy
      3、d[x-1] -    d[x]    <=    -1
     对于d[x] - d[y] <= z,令z = w(y, x),那么有 d[x] <= d[y] + w(y, x),所以当d[x] > d[y] + w(y, x),我们需要更新d[x]的值,这对应了最短路的松弛操作,于是问题转化成了求1到N的最短路。
       对于所有满足d[x] - d[y] <= z的不等式,从y向x建立一条权值为z的有向边。
      然后从起点1出发,利用SPFA求到各个点的最短路,如果1到N不可达,说明最短路(即上文中的T)无限长,输出-2。如果某个点进入队列大于等于N次,则必定存在一条负环,即没有最短路,输出-1。否则T就等于1到N的最短路。

      2、区间约束
     【例题2】给定n(n <= 50000)个整点闭区间和这个区间中至少有多少整点需要被选中,每个区间的范围为[ai, bi],并且至少有ci个点需要被选中,其中0 <= ai <= bi <= 50000,问[0, 50000]至少需要有多少点被选中。
      例如3 6 2 表示[3, 6]这个区间至少需要选择2个点,可以是3,4也可以是4,6(总情况有 C(4, 2)种 )。

      这类问题就没有线性约束那么明显,需要将问题进行一下转化,考虑到最后需要求的是一个完整区间内至少有多少点被选中,试着用d[i]表示[0, i]这个区间至少有多少点能被选中,根据定义,可以抽象出 d[-1] = 0,对于每个区间描述,可以表示成d[ bi ]  - d[ ai - 1 ] >= ci,而我们的目标要求的是 d[ 50000 ] - d[ -1 ] >= T 这个不等式中的T,将所有区间描述转化成图后求-1到50000的最长路。
      这里忽略了一些要素,因为d[i]描述了一个求和函数,所以对于d[i]和d[i-1]其实是有自身限制的,考虑到每个点有选和不选两种状态,所以d[i]和d[i-1]需要满足以下不等式:  0 <= d[i] - d[i-1] <= 1   (即第i个数选还是不选)
      这样一来,还需要加入 50000*2 = 100000 条边,由于边数和点数都是万级别的,所以不能采用单纯的Bellman-Ford ,需要利用SPFA进行优化,由于-1不能映射到小标,所以可以将所有点都向x轴正方向偏移1个单位(即所有数+1)。

      3、未知条件约束
      未知条件约束是指在不等式的右边不一定是个常数,可能是个未知数,可以通过枚举这个未知数,然后对不等式转化成差分约束进行求解。
     【例题3】
在一家超市里,每个时刻都需要有营业员看管,R(i)  (0 <= i < 24)表示从i时刻开始到i+1时刻结束需要的营业员的数目,现在有N(N <= 1000)个申请人申请这项工作,并且每个申请者都有一个起始工作时间 ti,如果第i个申请者被录用,那么他会连续工作8小时。
现在要求选择一些申请者进行录用,使得任何一个时刻i,营业员数目都能大于等于R(i)。
       i = 0 1 2 3 4 5 6 ... 20 21 22 23 23,分别对应时刻 [i, i+1),特殊的,23表示的是[23, 0),并且有些申请者的工作时间可能会“跨天”。
       a[i] 表示在第i时刻开始工作的人数,是个未知量
       b[i] 表示在第i时刻能够开始工作人数的上限, 是个已知量
       R[i] 表示在第i时刻必须值班的人数,也是已知量
       那么第i时刻到第i+1时刻还在工作的人满足下面两个不等式(利用每人工作时间8小时这个条件):
       当 i >= 7,        a[i-7] + a[i-6] + ... + a[i] >= R[i]                                     (1)
       当 0 <= i < 7,  (a[0] + ... + a[i]) + (a[i+17] + ... + a[23]) >= R[i]              (2)

       对于从第i时刻开始工作的人,满足以下不等式:
       0 <= i < 24,    0 <= a[i] <= b[i]                                                            (3)
       令 s[i] = a[0] + ... + a[i],特殊地,s[-1] = 0
       上面三个式子用s[i]来表示,如下:
       s[i] - s[i-8] >= R[i]                               (i >= 7)                                      (1)
       s[i] + s[23] - s[i+16] >= R[i]               (0 <= i < 7)                                  (2)
       0 <= s[i] - s[i-1] <= b[i]                     (0 <= i < 24)                                (3)
       
      仔细观察不等式(2),有三个未知数,这里的s[23]就是未知条件,所以还无法转化成差分约束求解,但是和i相关的变量只有两个,对于s[23]的值我们可以进行枚举,令s[23] = T, 则有以下几个不等式:
      
      s[i] - s[i-8] >= R[i]
      s[i] - s[i+16] >= R[i] - T
      s[i] - s[i-1] >= 0
      s[i-1] - s[i] >= -b[i]
      
      对于所有的不等式 s[y] - s[x] >= c,建立一条权值为c的边 x->y,于是问题转化成了求从原点-1到终点23的最长路。
      但是这个问题比较特殊,我们还少了一个条件,即:s[23] = T,它并不是一个不等式,我们需要将它也转化成不等式,由于设定s[-1] = 0,所以 s[23] - s[-1] = T,它可以转化成两个不等式:
      s[23] - s[-1] >= T
      s[-1] - s[23] >= -T
      将这两条边补到原图中,求出的最长路s[23]等于T,表示T就是满足条件的一个解,由于T的值时从小到大枚举的(T的范围为0到N),所以第一个满足条件的解就是答案。
      最后,观察申请者的数量,当i个申请者能够满足条件的时候,i+1个申请者必定可以满足条件,所以申请者的数量是满足单调性的,可以对T进行二分枚举,将枚举复杂度从O(N)降为O(logN)。
五、差分约束题集整理

    最短路
      Shortest Path                      ☆☆     单源最短路
      Shortest Path Problem              ☆☆     单源最短路 + 路径数
      HDU Today                          ☆☆     单源最短路
      Idiomatic Phrases Game             ☆☆     单源最短路
      Here We Go(relians) Again          ☆☆     单源最短路
      find the safest road               ☆☆     单源最短路
      Saving James Bond                  ☆☆     单源最短路
      A strange lift                     ☆☆     单源最短路
      Free DIY Tour                      ☆☆     单源最短路 + 路径还原
      find the safest road               ☆☆     单源最短路(多询问)
      Invitation Cards                   ☆☆     单源最短路
      Minimum Transport Cost             ☆☆     单源最短路 + 路径还原
      Bus Pass                           ☆☆     单源最短路
      In Action                          ☆☆     单源最短路 + 背包
      Choose the best route              ☆☆     单源最短路 + 预处理
      find the longest of the shortest   ☆☆     二分枚举 + 最短路
      Cycling                            ☆☆     二分枚举 + 最短路
      Trucking                           ☆☆     二分枚举 + 最短路
      Delay Constrained Maximum Capacity ☆☆     二分枚举 + 最短路
      The Worm Turns                     ☆☆     四向图最长路
      A Walk Through the Forest          ☆☆     按照规则求路径数
      find the mincost route             ☆☆     无向图最小环
      Arbitrage                          ☆☆     多源最短路
      zz's Mysterious Present            ☆☆     单源最短路
      The Shortest Path                  ☆☆     多源最短路
      Bus System                         ☆☆     单源最短路
      How Many Paths Are There           ☆☆     次短路
      WuKong                             ☆☆     两条最短路的相交点个数为P,要求最大化P
      Shortest Path                      ☆☆     多询问的最短路
      Sightseeing                        ☆☆     最短路和次短路的路径数
      Travel                             ☆☆     最短路径树思想
      Shopping                           ☆☆
      Transit search                     
      Invade the Mars                    
      Circuit Board                      
      Earth Hour                         
      Catch the Theves                   

    差分约束
      Layout                                  差分约束系统 - 最短路模型 + 判负环
      World Exhibition                        差分约束系统 - 最短路模型 + 判负环
      House Man                               差分约束系统 - 最短路模型 + 判负环
      Intervals                               差分约束系统 - 最长路模型 边存储用链式前向星
      King                                    差分约束系统 - 最长路模型 + 判正环
      XYZZY                                   最长路 + 判正环
      Integer Intervals                       限制较强的差分约束 - 可以贪心求解
      THE MATRIX PROBLEM                 ☆     差分约束系统 - 最长路模型 + 判正环
      Is the Information Reliable?            差分约束系统 - 最长路模型 + 判正环      
      Advertisement                           限制较强的差分约束 - 可以贪心求解
      Cashier Employment                      二分枚举 + 差分约束系统 - 最长路模型
      Schedule Problem                        差分约束系统 - 最长路模型
      Candies                            
      Burn the Linked Camp               
      Instrction Arrangement             
转自:http://www.cnblogs.com/murmured/p/5004082.html

差分约束系统就是给出一些形如x-y<=b不等式的约束,问你是否有满足问题的解,或者求最小,最大解。

这个问题的神奇之处是可以转化为图论的最短路问题。


一、预备知识:SPFA算法

详见我的最短路算法详解(Dijkstra/SPFA/Floyd)

二、差分约束的转化原理

对于图论的最短路径,有:对于d(v) <= d(u) + w(u, v) ,而差分约束系统的解法利用到了单源最短路径问题中的三角形不等式。

移项得:d(v) - d(u) <= w(u, v),是不是和上面的x-y<=b的一样?

是的,这就是转化为最短路径算法的原理。

三、建图

根据题目的意思进建图。

如POJ 1201 

题目大意:


有一个序列,题目用n个整数组合 [ai,bi,ci]来描述它,[ai,bi,ci]表示在该序列中处于[ai,bi]这个区间的整数至少有ci个。如果存在这样的序列,请求出满足题目要求的最短的序列长度是多少。
思路:

设s[i]为从1~i的整数个数。

这样对于区间[ a , b]显然有 S[b] - S[a-1] >=c[i] (为什么是a-1?因为闭区间a也要选上呀)

然后还有

0<= S[B]-S[B-1] <=1 (整数的话最多比前一个大一,好吧,我大二- -|||我不二啊!!)

变形得:

S[B]-S[B-1] >=0
S[B-1]-S[B]>=-1


四、用SPFA解需要注意的:

1.原图可能不是连通图,故需要加一个超级源点S,从S到任意的顶点边权为0,然后从该点出发。为什么?添加从虚点S到每个顶点的权为0的边.这是为了保证构造出来的图是连通的.由于虚点本身并不引入负圈,所以设置虚点以后最短路仍然存在,并且每个约束仍然满足.

或者差分约束不用什么附加顶点, 附加顶点的唯一用处就是保证图的连通性, 不让你有负环判不到的情况, 解决这种问题的最佳途径就是初始把所有顶点都加入队列, 并且将所有dis

置0, 这就相当于加了一个不存在的附加顶点, 它与所有的顶点的直连长度都是0.

当然推荐第二种,效率也高。


2.如果求最小的解,那么我们一开始把dis设为无穷小,并且使用最长路。即 if(d[v] < d[u]+w(u,v))    进行更新,而建图的时候也要用大于等于。

如果求最大,那么我们一开始把dis设为无穷大,使用最短路。

为什么?

问得好!(- -|||) 以求解最大的为例(最小解同理)dis[id]一开始为无穷大,图最短路更新的条件为: if(d[v]>d[u]+w(u,v))   d[v]=d[u]+w(u,v); 通过不断的松弛,使得d的值不断变小,直到满足所有条件,也就是说满足条件的时候就是最大的了~

那么,我们建图的时,都转化为A-B<=C这种形式,以(B为起点,向A连接一条权值为C的边) 因为图的最短路有:d[v]- d[u]<=w(u,v); 即( d[v]<=d[u]+w(u,v); )


所以,当你在纠结用小于号大于号的时候,看看题目求的是最大还是最小,如果只是判断有木有解,那么大于号小于都可以,只不过要注意全部等式要统一。


题目:

ZOJ 2770 Burn theLinked Camp差分约束 ZOJ排名第一~

POJ 1201 Intervals|| POJ 1716 Integer Intervals差分约束

POJ 2983 Is theInformation Reliable?依旧差分约束

POJ 1275 CashierEmployment挺难的差分约束题

POJ 1364 King (UVA515)差分约束

POJ 3159 Candies还是差分约束(栈的SPFA

POJ 3169 Layout差分约束

UVA 11478 - Halum差分约束

转自:http://972169909-qq-com.iteye.com/blog/1185527
KIDx 的解题报告 
 

先总结下: 

第一: 
感觉难点在于建图 
第二: 
①:对于差分不等式,a - b <= c ,建一条 b 到 a 的权值为 c 的边,求的是最短路,得到的是最大值 
②:对于不等式 a - b >= c ,建一条 b 到 a 的权值为 c 的边,求的是最长路,得到的是最小值 
③:存在负环的话是无解 
④:求不出最短路(dist[ ]没有得到更新)的话是任意解
 
第三: 
一种建图方法: 
设x[i]是第i位置(或时刻)的值(跟所求值的属性一样),那么把x[i]看成数列,前n项和为s[n],则x[i] = s[i] - s[i-1]; 
那么这样就可以最起码建立起类似这样的一个关系:0 <= s[i] - s[i-1] <= 1; 
其他关系就要去题目探索了 

回到上面那些题目: 

第一题:【POJ 1201/ZOJ 1508/HDU 1384 Intervals】 
http://poj.org/problem?id=1201 
题意:求符合题意的最小集合的元素个数 
设x[i]是{i}这个集合跟所求未知集合的交集元素个数,明显最大只能是1 
再设s[i] = x[0] + x[1] + …… + x[i] 
明显的,s[i]表示集合{0,1,2,3,……,i}与所求未知集合的交集元素个数 
那么就有x[i] = s[i] - s[i-1] 
∵0 <= x[i] <= 1 
∴0 <= s[i] - s[i-1] <= 1 
由于题目求最小值,所以是最长路,用的是a - b >= c这种形式 
即有:①s[i] - s[i-1] >= 0; ②s[i-1] - s[i] >= -1; 
按照题目输入a, b, c: 
表示{a,a+1,a+2,……,b}(设这个集合是Q)与所求未知集合的交集元素个数至少为c 
而s[a-1]表示{1,2,3,……,a-1}与所求未知集合的交集元素个数 
s[b]表示{1,2,3,……,a-1,a,a+1,a+2,……,b}与所求未知集合的交集元素个数 
∴Q = s[b] - s[a-1]; 
即可建立关系: ③s[b] - s[a-1] >= c; 
但是还有一个问题a >= 0,那么a-1有可能不合法 
解决方法:所有元素+1就可以了 
实现:把③变成 s[b+1] - s[a] >= c; 

第二题:【POJ 1275/ZOJ 1420/HDU 1529 Cashier Employment】 
http://poj.org/problem?id=1275 
文章最后有附上这题的代码。 
这题是这里面最难的一题,建图难,而且难以找出所有约束条件
 
先说明一下,这里我把编号设定为1-24,而不是题目的0-23,并且设0为虚点 
设x[i]是实际雇用i时刻开始工作的员工数 
R[i]是题目需要的i时刻正在工作的最少员工数 
注意了,i时刻开始工作i时刻正在工作是完全不同的 
设s[i] = x[1] + x[2] + …… + x[i] 
则s[i]表示1-i这段时间开始工作的员工数 
再设num[i]表示i时刻开始工作最多可以雇用的员工数 
∴有0 <= x[i] <= num[i] 
即 0 <= s[i] - s[i-1] <= num[i] 
由于是求最小值,所以用最长路 
则有:①s[i] - s[i-1] >= 0;②s[i-1] - s[i] >= -num[i]; 
(1 <= i <= 24,虽然0是虚点,但是s[1] - s[0]也是必要的!因为x[1]也是有范围的!
由于员工可以持续工作8个小时(R[i]是i时刻正在工作的最少人数) 
∴x[i-7] + x[i-6] + …… + x[i] >= R[i]【i-7开始工作的人在i时刻也在工作,其他同理】 
即:③s[i] - s[i-8] >= R[i] (8 <= i <= 24
但是有个特殊情况,就是从夜晚到凌晨的一段8小时工作时间 
(x[i+17] + …… + x[24]) + (x[1] + x[2] + …… + x[i]) >= R[i]; 
则:s[24] - s[i+16] + s[i] >= R[i]; 
整理一下:④s[i] - s[i+16] >= R[i] - s[24]
(1 <= i < 8,注意i=0是没有意义的,因为R[0]没有意义
由于s[24]就是全天实际雇用的人数,而一共有n个员工可以雇用 
所以设ans = s[24] 
则:⑤s[i] - s[i+16] >= R[i] - ans;( 1 <= i < 8 ) 
所以就可以从小到大暴力枚举ans【或二分枚举】,通过spfa检验是否有解即可【存在负环无解】 
但是还有一个问题,起点在哪里…… 
这时候虚点0就起作用了,我称它为超级起点 
于是建图后直接判断spfa(0)是否有解就可以了 
PS:还有另外一个条件必须用到……:⑥s[24] - s[0] >= ans] 
不用这个条件二分枚举ans可以AC,但这只是数据问题,暴力从小到大枚举木有这条件就会错,所以说这个条件最关键而又难找……要仔细找特殊点和虚点的约束关系 

第三题:【POJ 1364/ZOJ 1260/HDU 1531 King】 
http://poj.org/problem?id=1364 
设s[i] = a[1] + a[2] + …… + a[i]; 
a[Si] + a[Si+1] + ... + a[Si+ni] = s[Si+ni] - s[Si-1]; 
所以由题意有: 
①s[Si+ni] - s[Si-1] > ki 
或②s[Si+ni] - s[Si-1] < ki 
由于只是检验是否有解,所以最短路或最长路都可用,以下是最短路要建立的关系: 
把①化为:s[si-1] - s[si+ni] <= - ki - 1 
把②化为:s[si+ni] - s[si-1] <= ki - 1 

第四题:【ZOJ 1455/HDU 1534 Schedule Problem】 
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1455 
设第i项工作持续时间为v[i],开始时间s[i],那么结束时间就是s[i]+v[i] 
SAS: s[a] >= s[b] ---> s[a] - s[b] >= 0 
FAS: s[a] + v[a] >= s[b] ---> s[a] - s[b] >= -v[a] 
SAF: s[a] >= s[b] + v[b] ---> s[a] - s[b] >= v[b] 
FAF: s[a] + v[a] >= s[b] + v[b] ---> s[a] - s[b] >= v[b] - v[a]
 
直接最长路建图就可以了 

第五题:【HDU 3440 House Man】 
http://acm.hdu.edu.cn/showproblem.php?pid=3440 
此题难度仅次于第二题,需要深刻理解差分约束 
题意:按照序号从左往右放置房子,求最后从低到高跳到所有房子的【最大总水平路程】 
设s(b) - s(a) <= K(一个常数)表示【设a,b为序号】: 
b到a的距离 <= K,但是必须定一个规则,a在左边还是b在左边? 
这里设a,b是x轴上的点,再设b > a 
所以这样的情况下规则就是:【s(序号大的) - s(序号小的)】才表示:【b到a之间的距离】这个意义
当然可以设另一种规则---【序号小-序号大】表示距离---,总之要一致! 
按照第一种规则有以下关系: 
①位置相邻: 
s(i) - s(i-1) >= 1 ---> s(i-1) - s(i) <= -1 
②高度相邻(排序后):【num表示a[i]这间房子的序号】 
s(max(a[i].num,a[i-1].num))-s(min(a[i].num,a[i-1].num)) <= D 
建图后只要这样: 
spfa (min (a[1].num, a[n].num)); 
printf ("%d\n", dist[max (a[n].num, a[1].num)]);
 
答案就出来了 
另外推荐这种方法!比较简单:http://hi.baidu.com/tju_ant/blog/item/f22fe6d92809033833fa1c08.html 

第六题:【HDU 3592 World Exhibition】 
http://acm.hdu.edu.cn/showproblem.php?pid=3592 
按照题目明显条件建立关系式立刻水过 
但是我觉得它数据很水…… 
题目说:Assume that there are N (2 <= N <= 1,000) people numbered 1..N who are standing in the same order as they are numbered 
也就是说人是按序号排的啊 
那应该还有一个约束条件才对吧:s(i) - s(i-1) >= 0; 
就像这组数据: 

3 2 1 
1 2 1 
1 3 2 
2 3 3 
要按序号排队不可能满足,应该输出-1 
总之要不要这个约束条件都能AC……我特么的彻底无语了 


第七题:【HDU 3666 THE MATRIX PROBLEM】 
http://acm.hdu.edu.cn/showproblem.php?pid=3666 
这题spfa用队列卡数据容易超时,用栈吧…… 
由题意得对于矩阵每个元素【设为w,处于矩阵第i行,第j列】 
L <= w*a[i]/b[j] <= U 
两边取对数有: 
lg(L) <= lg(w)+lg(a[i])-lg(b[j]) <= lg(U) 
按照最长路整理得【也可以用最短路】: 
①lg(a[i])-lg(b[j]) >= lg(L)-lg(w);②lg(b[j])-lg(a[i]) >= lg(w)-lg(U) 
把a和b数组合并成一个数组s得【a有n个元素,b有m个元素,这里把b接在a数组后面】: 
①s(i) - s(j+n) >= lg(L) - lg(w) 
②s(j+n) - s(i) >= lg(w) - lg(U)
 
最后加个超级起点即可 
我把0作为超级起点: 
for (i = 1; i <= n + m; i++) 
    addedge (0, i, 0); 
spfa (0); 



最后弱弱的献上第二题代码: 
C++代码  收藏代码
  1. #include <iostream>  
  2. #include <queue>  
  3. using namespace std;  
  4. #define inf 0x7fffffff  
  5. #define M 25  
  6.   
  7. struct edge{  
  8.     int v, w, next;  
  9. }e[5*M];  
  10. bool inq[M];  
  11. int dist[M], pre[M], n = 24, cnt, ind[M];  
  12.   
  13. void init ()  
  14. {  
  15.     memset (pre, -1, sizeof(pre)); cnt = 0;  
  16. }  
  17. void addedge (int u, int v, int w)  
  18. {  
  19.     e[cnt].v = v; e[cnt].w = w; e[cnt].next = pre[u]; pre[u] = cnt++;  
  20. }  
  21. bool spfa (int u)  
  22. {  
  23.     int i, v, w;  
  24.     for (i = 0; i <= n; i++)  
  25.     {  
  26.         dist[i] = -inf;  
  27.         inq[i] = false;  
  28.         ind[i] = 0;  
  29.     }  
  30.     queue<int> q;  
  31.     q.push (u);  
  32.     inq[u] = true;  
  33.     dist[u] = 0;  
  34.     while (!q.empty())  
  35.     {  
  36.         u = q.front();  
  37.         if (++ind[u] > n)  
  38.             return false;  
  39.         q.pop();  
  40.         inq[u] = false;  
  41.         for (i = pre[u]; i != -1; i = e[i].next)  
  42.         {  
  43.             v = e[i].v;  
  44.             w = e[i].w;  
  45.             if (dist[u] + w > dist[v])  
  46.             {  
  47.                 dist[v] = dist[u] + w;  
  48.                 if (!inq[v])  
  49.                 {  
  50.                     q.push (v);  
  51.                     inq[v] = true;  
  52.                 }  
  53.             }  
  54.         }  
  55.     }  
  56.     return true;  
  57. }  
  58.   
  59. int main()  
  60. {  
  61.     int t, R[M], num[M], i, pos, m, l, r, ans;  
  62.     scanf ("%d", &t);  
  63.     while (t--)  
  64.     {  
  65.         for (i = 1; i <= n; i++)  
  66.             scanf ("%d", R+i);  
  67.         scanf ("%d", &m);  
  68.         memset (num, 0, sizeof(num));  
  69.         for (i = 0; i < m; i++)  
  70.         {  
  71.             scanf ("%d", &pos);  
  72.             num[pos+1]++;  
  73.         }  
  74.         l = 0, r = m;  
  75.         bool flag = true;  
  76.         while (l < r)        //二分枚举ans  
  77.         {  
  78.             init();  
  79.             ans = (l+r) / 2;  
  80.             for (i = 1; i <= n; i++)  
  81.             {  
  82.                 addedge (i-1, i, 0);            //s[i] - s[i-1] >= 0  
  83.                 addedge (i, i-1, -num[i]);      //s[i-1] - s[i] >= -num[i]  
  84.             }  
  85.             for (i = 8; i <= n; i++)  
  86.                 addedge (i-8, i, R[i]);         //s[i] - s[i-8] >= R[i]  
  87.             for (i = 1; i < 8; i++)  
  88.                 addedge (i+16, i, R[i]-ans);    //s[i] - s[i+16] >= R[i] - ans  
  89.             addedge (0, 24, ans);               //s[24] - s[0] >= ans  
  90.             if (spfa (0))  
  91.                 r = ans, flag = false;  
  92.             else l = ans + 1;  
  93.         }  
  94.         if (flag)  
  95.             puts ("No Solution");  
  96.         else printf ("%d\n", r);  
  97.     }  
  98.     return 0;  
  99. }  
转自:http://blog.csdn.net/qq_24451605/article/details/47121853

差分约束系统只是对最短路算法的一种应用,没有什么新的算法,只是对于具体问题的建图方法的确定

----------------------------------------------差分约束系统解决的问题描述---------------------------------------------------------

差分约束系统解决的问题是不等式组的求解:

X1 - X2 <= 0
X1 - X5 <= -1
X2 - X5 <= 1
X3 - X1 <= 5
X4 - X1 <= 4
X4 - X3 <= -1
X5 - X3 <= -3
X5 - X4 <= -3

这就是一个不等式组,给出的不等式组只存在小于等于号,如果有个别的式子是大于等于,我们可以通过两边同时乘-1的得到统一的不等号方向的不等式组。

这个不等式组一定是无解和无数解两种情况,因为如果是存在任意一组解,{x1,x2,x3,x4,x5},我们都可以通过{x1+k,x2+k,x3+k,x4+k,x5+k}得到一个新的解。所以解的个数是无数的。

因为每个数都加k,他们任意两个数之间的差是不变的,所以对于不等式没有影响。

------------------------------------解决差分约束问题的建图方法-及解决方案-------------------------------------------------------

1.对于一个全部都是<=号的不等式组,我们可以将每个式子转化为Xi<=Xj+W(i,j),那么就建一条边,Xj->Xi=W(i,j),然后利用最短路径解决问题,在x0定死的情况下,求得最小值

2.对于一个全部都是>=号的不等式组,我们可以将每个式子转化为Xi>=Xj+W(i,j),那么就建一条边,Xj->Xi=W(i,j),然后利用最长路径解决问题,在x0定死的情况下,求得最大值

如果dis[Xi]为inf或-inf,那么Xi为任意解

如果求最短路的过程中出现负环,那么说明该不等式组无解

--------------------------------------建图方法和解决方案的证明-------------------------------------------------------------------------

1.我们在这里规定dis[x]就是xi的值,那么在最短路的结果中中我们保证的是如果存在两点相连,dis[i]-dis[j] <= w(i,j),正好和不等式组中的式子相符,x0定死,相当于给原点dis[S]==C一个固定的常数值,那么相当于dis[i]求取的都是最小的,那么相当于得到了最小解

2.>=号和最长路的对应关系类似

3.当dis[Xi]==inf 或者 -inf时,那么证明,当前点和原点之间不存在一条路径,那么不能够得到一组确定的解,没有最优解

4.当出现负环的时候,证明无解,因为存在负环的时候,

Xi <= Xj + a

Xj <= Xi + b

若a+b<0的时候存在负环,

这时

两式相加,Xi+Xj <= Xi+Xj+a+b,若a+b<0

那么0<= a+b ,矛盾!!

所以方程无解


原创粉丝点击