<学习笔记> 查分约束系统

定义:如果一个系统由n个变量和m个约束条件组成,形成m个形如 ai - aj ≤ k 的不等式(i,j∈[1,n],k为常数),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。

栗子:给出这样的一组不等式

         A-B < = 3

               B-C < = 6

               C-D < = 5

               E-C < = 2

               B-E < = 3

      A-D的最大值。

   经过一番脑跑之后,得出答案13。但是我们不能总是脑跑啊。。。费脑子QAQ,所以有什么科学的求法吗??

   我们对A-B < = 3进行移项,改为 A < = B + 3 ,发现类似于最短路中的不等式 de[t] < =  de[f] + d ,可以看做是从B到A连了一条权值为3的边。我们把上面的不等式画成图。

  

发现答案即为D到A的最短路。

为什么呢??

把图单个剥离出来看

已知 (1) B-A < = x ;(2) C - B < = Y ;(3) C - A < = z .

C-A 的最大值 即为 1+2 和 3 比较 ,也就是 C-A<=x+yC-A <=z 答案即为 min(x+y,z) (小小取更小),即为从A到C的最短路。

字面理解为B比A最大大x,C比B最大大y,C就比A最大大x+y,C又比A最大大z,所以我们要求一个x+y和z的最小值。

把它扩展为n个点,m条边的图,每一条边都是一个可传递的大小关系。S到T的路径可以看做许多S与T之间的大小关系(T-S < = ... ),我们要求的T-S的最大值就是最小的限制,也就是A到C最短路。

同理 B-A > = x , C-B > = y , C-A > = z ,也可以抽象为 de[t] > = de[f] + d ,这就转变为了最长路问题 ,这是求 C-A 的最小值 , 与上面思想相同。

也就是最大求最短,最小求最长。

关于Dist[]的初始化
1.如果将源点到各点的距离初始化为0,最终求出的最短路满足它们之间相互最接近了
2.如果将源点到各点的距离初始化为INF(无穷大),其中之1为0,最终求出的最短路满足 它们与该点之间相互差值最大。(from  baidubaike)

但是题目里给出的不等式不一定大于小于号的方向相同,如 求最大值时却给出了 D-E > = q , 只需要转化成 E-D < = -q 就可以了。(D到E连了一条边权为-q的边)。

那么问题又来了,不等式一定有解吗??

不一定。

数学上,多个不等式的解集分为 空集 , 有限集,无限集(暂且这么叫qwq)。

发现,若是S无法到T,即为无限多解(没有限制)。若S到T的路径上有环(最短路的负环,最长路的正环),无法取到最大值或最小值。

emmm。。。百度百科上的有关知识

引理:设x=(x1,x2,…,xn)是差分约束系统Ax≤b的一个解,d为任意常数。则x+d=(x1+d,x2+d,…,xn+d)也是该系统Ax≤b的一个解。

定理:将如上差分约束系统转换成图后,以为源点得到的最短路径序列为(如果有解),则满足且若任意解,则有

 

查查分约束时查到的神犇博客,十分详细易理解%%%

栗子 : codevs 2404 糖果

代码 qwq

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<deque>
 7 using namespace std;
 8 
 9 int N,K,X,A,B,cnt,f;
10 int first[100010],next[400010],rd[100010];
11 long long de[100010],ans;
12 bool used[100010];
13 
14 struct maple{
15    int f,t,d;    
16 }Rode[400010];
17 deque<int> q;   
18 
19 void Build(int f,int t,int d)
20 {
21     Rode[++cnt]=(maple){f,t,d};
22     next[cnt]=first[f];
23     first[f]=cnt;
24 }
25 void SPFA() // 跑最长路
26 {
27     used[0]=1;
28     de[0]=1;  // 保证每个人都分到糖果 
29     q.push_back(0);
30     while(!q.empty())
31     {
32         int a=q.front();
33         q.pop_front();
34         used[a]=0;
35         for(int i=first[a];i;i=next[i]) 
36            if(de[Rode[i].t]<de[a]+Rode[i].d)
37            {
38                   de[Rode[i].t]=de[a]+Rode[i].d;
39                   if(!used[Rode[i].t])
40                   {
41                          used[Rode[i].t]=1;
42                          if(!q.empty()&&de[Rode[i].t]>=de[q.front()]) q.push_front(Rode[i].t);
43                          else q.push_back(Rode[i].t);
44                          ++rd[Rode[i].t];
45                          if(rd[Rode[i].t]>=N)  // 判断是否有解  
46                          {
47                                 f=1;
48                                 break;
49                          }
50                   }
51            }
52         if(f) break;
53     }
54 }
55 int main()
56 {
57     scanf("%d%d",&N,&K);
58     for(int i=1;i<=K;++i)
59     {
60         scanf("%d%d%d",&X,&A,&B);
61         if(X==1) Build(A,B,0),Build(B,A,0); // A = B 
62         if(X==2) Build(A,B,1);   // B - A > = 1
63         if(X==3) Build(B,A,0);   // A - B > = 0
64         if(X==4) Build(B,A,1);   // A - B > = 1
65         if(X==5) Build(A,B,0);   // B - A > = 0
66     }
67     for(int i=1;i<=N;++i) Build(0,i,0); // i - 0 > = 0  
68     SPFA();
69     if(f) cout<<-1;
70     else{
71         for(int i=1;i<=N;++i)
72            ans+=de[i];
73         printf("%lld",ans);
74     }
75     return 0;
76 }

 

(部分内容参考自各神犇博客,侵删 qwq)

 

posted @ 2017-11-07 16:38  loi_maple  阅读(229)  评论(0编辑  收藏  举报