差分约束

看了网上一下内容,整理出来供大家参考,其实想想最小值怎么写,求最大值怎么写,这个我觉得蛮有意思的。

1.问题定义

    差分约束系统属于线性规划问题。在一个差分约束系统中,线性规划矩阵A的每一行包含一个1和一个-1,A的所有其他元素都为0。因此,由Ax≤b给出的约束条件是m个差分约束集合,其中包含n个未知元。每个约束条件为如下形式的简单线性不等式:xj-xi≤bk(1≤i, j≤n,1≤k≤m)。如下图5维向量x满足8个不等式的差分约束,我们可以把未知量x1,x2,x3,x4,x5化为如下8个不等式:

我们可以发现当x=(x1,x2,…,xn)是差分约束系统Ax≤b的一个解,d为任意常数。则x+d=(x1+d,x2+d,…,xn+d)也是该系统Ax≤b的一个解。因此这个不等式组要么无解,要么就有无数组解。

 

2.解决方案

    求解差分约束系统,可以转化成图论的单源最短路径问题。观察xj-xi<=bk,会发现它类似最短路中的三角不等式d[v] <= d[u] +w[u,v],即d[v] - d[u] <=w[u,v]。因此,以每个变量xi为结点,对于约束条件xj-xi<=bk,连接一条边E(i,j),边权为bk。求单源最短路径,必须有一个源点,然后再求这个源点到其他所有点的最短路径,我们可以增加一个原点s与所有其他点相连,边权均为0,xi - x0 <= 0。上图中的不等式于是转化为下图中的有向图:



    下面介绍解决差分约束问题的方法:Bellman-Ford算法。Bellman-Ford算法是用来解决有向图中存在负权边的单源最短路径问题的。

①将除源点外的所有顶点的最短距离估计值,即d[v] = +∞, d[s] = 0;

②反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;

③判断边集E中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,问题有解,并且从源点可到达的顶点v的最短距离保存在d[v]中。

算法伪代码如下:

Bellman-Ford()
{
   for each vertex v ∈ G do             //初始化

         d[v] = +∞

   d[s] = 0

  

   for i = 1 to n-1 do

      for each edge(u, v) ∈ G do

         if d[v] > d[u] + w(u, v) then   //松弛操作

            d[v] = d[u] + w(u, v)

 

   for each edge(u, v) ∈ G do

       if d[v] > d[u] + w(u, v) then    //检查是否存在回路

          return false

   return true

 }

图中任意一条最短路径既不能包含负权回路,也不会包含正权回路,所以最多包含n-1条边,从源点s出发每进行一遍松弛操作时,多生成了了从s出发层次为1的树,而最短边路径最多为n-1,故只需要循环n-1次。最后计算的d[v]即为差分不等式的一组解。

 

3.算法优化

    Bellman-Ford算法的时间复杂度为O(VE),一种方法是我们引入SPFA算法作为其优化算法,也就是进行队列优化,初始化时将源s加入队列每次从队列中取出一个元素,并且对所有与之相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队,直到队列为空时SPFA算法结束。SFPA的期望时间复杂度为O(KE)[己考证,证明不严密,最坏情况和Dijkstra差不多],期望的常数K一般不会超过2。另一种优化是Yen优化,将图中的点随机的进行标记序号v1,v2,vi...,则分为两类边集合:                                   

进行松驰时,先按vi的升序只找Ef边进行松弛,然后再按vi的降序只对Eb边进行松弛,可以优化为常数时间,复杂度仍为O(VE)[己考证]。

 

POJ 1201

本题的题意是给了我们一些区间,然后告诉每个区间中至少需要取Ci个数。求出满足n个条件的集合C的最少的元素个数。

首先第一个转化,是找到一个合理的表示。用ti表示每一个数,如果有用就是1,否则是0。吧S(i+1)定义成S(i+1)=sigma(tj)(1<=j<=i)也就是。S[i+1]表示从0到i有多少个数是需要的。

因此,题目中的条件可以表示成S[bi+1]>=S[ai]+Ci//至少要Ci个

D[v]>=D[u]+w(u,v)

上式对任何u成立,所以v应该是里面最大的,若D[v]<D[u]+w(u,v)则D[v]=D[u]+w(u,v)

于是。可以从ai和bi+1连一条线,它的长度是ci

这里只有这些条件还是不够的,还要加上两个使其满足整数性质的条件

1>=s[i+1]-s[i]>=0

有了这么多条件,使其自然构成了一个差分约束系统。

用spfa算法得到一个最长路,第一个到最后一个节点的最长路即是需要求的值。

 

 

 

节点i还有一条边指向i+1,权值为1,一条边指向i-1权值为-1

 

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<vector>

#include<queue>

using namespace std;

const int MAXN =50005;

struct node{

    int w;

    int v;

    node(int ww= 0,int vv = 0){

        w = ww;

        v = vv;

    }

};

const int INF = -9999;

int dis[MAXN];

vector<node>  a[MAXN];

int maxs,mins;

void spfa(){

    boolvisit[MAXN];

    memset(visit,false,sizeof(visit));

    for(int i = mins;i<=maxs;i++)dis[i] = INF;

    queue<int>qe;

    qe.push(mins);

    visit[mins] = 1;

    dis[mins] = 0;

    while(!qe.empty()){

        int cur= qe.front();

        qe.pop();

        visit[cur] = false;

        int s =a[cur].size();

        for(int i = 0;i<s;i++){

            if(dis[cur]>dis[a[cur][i].v]-a[cur][i].w){

                dis[a[cur][i].v] =dis[cur]+a[cur][i].w;

                if(!visit[a[cur][i].v]){

                    visit[a[cur][i].v] = true;

                    qe.push(a[cur][i].v);

                }

            }

        }

    }

}

int main()

{

    int n;

    maxs =0;

    mins = 99999;

    scanf("%d",&n);

    while(n--){

        intv,u,w;

        scanf("%d%d%d",&u,&v,&w);

        a[u].push_back(node(w,v+1));

        if(maxs<v)maxs= v;

        if(mins>u)mins= u;

    }

    maxs++;

    for(int i = mins;i<=maxs;i++){

        a[i].push_back(node(0,i+1));

        a[i+1].push_back(node(-1,i));

    }

    spfa();

    printf("%d\n",dis[maxs]);

    return 0;

}

 

 

 

 

最短路或者最长路如何区分:

 

 

(本文假设读者已经有以下知识:最短路径的基本性质、Bellman-Ford算法。)
    比如有这样一组不等式:
   

     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)


    全都是两个未知数的差小于等于某个常数(大于等于也可以,因为左右乘以-1就可以化成小于等于)。这样的不等式组就称作差分约束系统。
    这个不等式组要么无解,要么就有无数组解。因为如果有一组解{X1, X2, ..., Xn}的话,那么对于任何一个常数k,{X1+ k, X2 + k, ..., Xn + k}肯定也是一组解,因为任何两个数同时加一个数之后,它们的差是不变的,那么这个差分约束系统中的所有不等式都不会被破坏。
    
    差分约束系统的解法利用到了单源最短路径问题中的三角形不等式。即对于任何一条边u -> v,都有:

d(v) <= d(u) + w(u, v)


    其中d(u)和d(v)是从源点分别到点u和点v的最短路径的权值,w(u, v)是边u -> v的权值。
    显然以上不等式就是d(v) - d(u) <= w(u,v)。这个形式正好和差分约束系统中的不等式形式相同。于是我们就可以把一个差分约束系统转化成一张图,每个未知数Xi对应图中的一个顶点Vi,把所有不等式都化成图中的一条边。对于不等式Xi - Xj <= c,把它化成三角形不等式:Xi <= Xj + c,就可以化成边Vj -> Vi,权值为c。最后,我们在这张图上求一次单源最短路径,这些三角形不等式就会全部都满足了,因为它是最短路径问题的基本性质嘛。
    话说回来,所谓单源最短路径,当然要有一个源点,然后再求这个源点到其他所有点的最短路径。那么源点在哪呢?我们不妨自已造一个。以上面的不等式组为例,我们就再新加一个未知数X0。然后对原来的每个未知数都对X0随便加一个不等式(这个不等式当然也要和其它不等式形式相同,即两个未知数的差小于等于某个常数)。我们索性就全都写成Xn - X0 <= 0,于是这个差分约束系统中就多出了下列不等式:
    

      X1 - X0 <= 0
      X2 - X0 <= 0
      X3 - X0 <= 0
      X4 - X0 <= 0
      X5 - X0 <= 0

不等式组(2)


    对于这5个不等式,也在图中建出相应的边。最后形成的图如下:


图1

    图中的每一条边都代表差分约束系统中的一个不等式。现在以V0为源点,求单源最短路径。最终得到的V0到Vn的最短路径长度就是Xn的一个解啦。从图1中可以看到,这组解是{-5, -3, 0, -1, -4}。当然把每个数都加上10也是一组解:{5, 7, 10, 9, 6}。但是这组解只满足不等式组(1),也就是原先的差分约束系统;而不满足不等式组(2),也就是我们后来加上去的那些不等式。当然这是无关紧要的,因为X0本来就是个局外人,是我们后来加上去的,满不满足与X0有关的不等式我们并不在乎。
    也有可能出现无解的情况,也就是从源点到某一个顶点不存在最短路径。也说是图中存在负权的圈。这一点我就不展开了,请自已参看最短路径问题的一些基本定理。

    其实,对于图1来说,它代表的一组解其实是{0, -5, -3, 0, -1, -4},也就是说X0的值也在这组解当中。但是X0的值是无可争议的,既然是以它作为源点求的最短路径,那么源点到它的最短路径长度当然是0了。因此,实际上我们解的这个差分约束系统无形中又存在一个条件:

    X0 = 0


    也就是说在不等式组(1)、(2)组成的差分约束系统的前提下,再把其中的一个未知数的值定死。这样的情况在实际问题中是很常见的。比如一个问题表面上给出了一些不等式,但还隐藏着一些不等式,比如所有未知数都大于等于0或者都不能超过某个上限之类的。比如上面的不等式组(2)就规定了所有未知数都小于等于0。
    
    对于这种有一个未知数定死的差分约束系统,还有一个有趣的性质,那就是通过最短路径算法求出来的一组解当中,所有未知数都达到最大值。下面我来粗略地证明一下,这个证明过程要结合Bellman-Ford算法的过程来说明。
    假设X0是定死的;X1到Xn在满足所有约束的情况下可以取到的最大值分别为M1、M2、……、Mn(当然我们不知道它们的值是多少);解出的源点到每个点的最短路径长度为D1、D2、……、Dn。
    基本的Bellman-Ford算法是一开始初始化D1到Dn都是无穷大。然后检查所有的边对应的三角形不等式,一但发现有不满足三角形不等式的情况,则更新对应的D值。最后求出来的D1到Dn就是源点到每个点的最短路径长度。
    如果我们一开始初始化D1、D2、……、Dn的值分别为M1、M2、……、Mn,则由于它们全都满足三角形不等式(我们刚才已经假设M1到Mn是一组合法的解),则Bellman-Ford算法不会再更新任合D值,则最后得出的解就是M1、M2、……、Mn。
    好了,现在知道了,初始值无穷大时,算出来的是D1、D2、……、Dn;初始值比较小的时候算出来的则是M1、M2、……、Mn。大家用的是同样的算法,同样的计算过程,总不可能初始值大的算出来的结果反而小吧。所以D1、D2、……、Dn就是M1、M2、……、Mn。
    
    那么如果在一个未知数定死的情况下,要求其它所有未知数的最小值怎么办?只要反过来求最长路径就可以了。最长路径中的三角不等式与最短路径中相反:

d(v) >= d(u) + w(u, v) 
也就是 d(v) - d(u) >= w(u, v)


    所以建图的时候要先把所有不等式化成大于等于号的。其它各种过程,包括证明为什么解出的是最小值的证法,都完全类似。

 

 

总之求最大值就化成>=,求最小值就化为<=

 

你可能感兴趣的:(c,算法,优化,struct,BI,each)