差分约束系统

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

假设有如下不等式组:

X2-X1<=1

X4-X3<=4

X5-X2<=3

........

求解这个不等式组

首先我们将不等式变形

X2<=X1+1

X4<=X3+4

X5<=X2+3

.......

即将每个不等式化为Xi<=Xj+c的形式,这个方程组就是约束方程组。

观察这个形式,我们发现和图论中单源最短路径的过程很相似。即dis[i]表示点i到点0的最短距离,则 dis[i]<=dis[j]+w(j,i),j!=i。我们根据一个不等式Xi<=Xj+c 可以看做是2个点i和j,Xi表示i点到0点的最短距离,连一条从j指向i且权为c的边,这样一定有dis[i]<=dis[j]+w(j,i), 即满足了Xi<=Xj+c。我们将所有约束方程转化为点和边,就构成了一个有向图,这个图就是约束图。在约束方程完备的情况下,只要求解这个图的单 元最短路径就可以了。

我们再观察约束方程发现,如果有一组解(X1,X2....)满足,那么(X1+d,X2+d...)一定也满足,也就是说满足该方程组的解有无数 多个。但是如果我们指定了一个变量的值,比如X0=0,在约束图中表现为dis[0]=0,那么方程组的解就不是无限多个了。我们刚才是按照Xi& lt;=Xj+c的形式建图,如果将其变形为Xj>=Xi-c,那么就是加一条从i指向j的权为-c的边,这个约束方程下就是求单元最长路径了。也 就是说同样一组方程我们既可以按最短路建立约束图也可以按最长路建立约束图,他们的区别在于,当某一个变量给定时,求最短路使其他变量在满足约束条件的情 况下达到最大值,求最长路则是达到最小值。我们可以根据题意决定按哪种方式建图,也就是看题目是要求最大值还是最小值。


例题1:

poj1364 King
题目:http://poj.org/problem?id=1364

题目是说是否存在一个数列{An},使得给出数组条件,每个条件是Ai + Ai+1 +...+Ai+b > c(<c),我们可以假设存在这样的数列,Sn为第0项到第n项的和,则每一组条件都可以转化为Si+j+1-Si>c或<c的形式。
注意到本题的约束是>和<,然而我们需要的是>=或者<=,所以必须有所转化。幸好是整数规划,所以我们可以转化如下:
x<a -》 x<=a-1
x>b -》 x>=b+1
然而需要注意的是,差分约束必须保证所有的不等式具有同样的不等号才能正确运行!所以我们把所有符号转为<=,然后构图。之后求最短路,如果可以求出则存在这样的数列,反之不可以。

关于求最短路,我们一般用的事Dijkstra,但是在做差分约束系统时,约束图并不是现实中的路,会存在负边,也会存在负环,这个时候我们就要用Bellman-ford了。

Bellmanford:

 For (l=1;l<点数;l++)

   {

For (每个边(i,j,w),w为权)

  {

If (dis[i]+w<dis[j])

  Dis[j]=dis[i]+w;

     }//这个过程称作一次“松弛”操作


          }//以上是求最短路,如果换<为>就是最长路,预处理dis[]=999999999,dis[源]=0

//最后再判断是否有负环:


For (每个边(i,j,w),w为权)

  {

If (dis[i]+w<dis[j])

  有负环;

     }


对于这种算法,邻接表是比较合适的,复杂度O(VE)。这道题就可以通过这种算法,如果最终求得没有负环则可以找到要求的数列,反之则不能。

实际上在处理差分约束系统时,约束图往往是比较大的,一般都要用邻接表存,而Bellman-ford的复杂度比较高。仔细观察我们发现,算法共进 行n-1次,每次对所有边进行松弛,而实际操作中,很多边是不需要松弛的,只有那些起点的dis值不是无穷的边才有必要松弛。在此基础上我们可以优化该算 法,用一个队列(或栈)存储需要松弛的边的起点,这个算法就是SPFA算法:

C[i]表示一个点的入队次数,in[i]表示该点是否在队列中

     源点入队;

      In[源]=1;

      C[源]=1;

   While(队列不空)

{

  i=出队;

 In[i]=0;

  For (所有的边(i,j,w))

If (dis[i]+w<dis[j])

{dis[j]=dis[i]+w;

If (j不在队列)

 {j入队;

In[j]=1;

C[j]++;

If (c[j]>边数)

Return 存在负环;


}

}

}

这里我们只用判断点入队次数是否大于点数就可以了,因为Bellman-ford中执行点数-1次。SPFA算法就是用队列(或栈)优化的Bellman-ford算法,求解差分约束系统一般就用这个方法。

 

例题2:

POJ1201 Intervals
题目:http://poj.org/problem?id=1201


题目是说要求你取若干数,满足每一组a,b,c,使得区间[a,b]中至少取了c个数,问至少要取多少个?

我们可以设Sn表示[0,n)区间内取的数有多少个,则对于每个a,b,c,都可以表示为

Sb+1-Sa>=c;这样就又是一个差分约束系统了。这里我们要求最长路(因为要按>=号建图),但是这里要注意,题目中还有隐含条件,显然1 >= Si+1 - Si >=0,我们要把这n组条件添加进去,否则会求出错误的答案。

再进一步考虑,题目中的数的范围有50000,对于这样一个图用SPFA也是开销很大的,而如果不加处理,就算只有一个约束,比如[1,5]中至少去2个,我们建图仍然要建立50000个点!而实际上,其实只用2个点就足够了。所以,我们要对数据进行处理。

考虑这样2个区间:

[1,6]   [3,5]

他们和

[1,4]  [2,3]

的覆盖关系是一样的。我们可以把前者映射到后者上,即把每个区间的起点和终点排序,分别映射1,2,3....n,这样一来,既没有改变区间之间的 关系,又把点的范围缩小在了n。这个过程就是离散化。经过离散化的数据不论原先是什么范围,甚至是实数,都可以映射到有限个点上。

这道题经过离散化后就不会超时了,注意的是原先的1 >= Si+1   -   Si>=0也要修改为

X >= Si+x  -  Si>=0,因为经过离散化后的点就不是连续的了。

 

 

总结

差分约束系统就是对一组不等式构成的约束条件下求解。可以化为图的模型,求最短路或最长路来做,最短路对应变量的最大值,最长路对应变量的最小值。 建图要按不等号(>= or <=)建,存图尽量用邻接表,求解SPFA,注意判负环。还有就是约束条件要完整,注意题目隐含的约束条件。

 

posted @ 2012-05-30 21:48  cseriscser  阅读(418)  评论(0编辑  收藏  举报