• 差分约束


     

    差分约束系统

    一、概念

     
                      如果一个系统由n个变量和m个约束条件组成,形成m个形如ai-aj≤k的不等式(i,j∈[1,n],k为常数),则称其为差分约束系统。
     

    二、引例

     
    给定n个变量和m个不等式,每个不等式的形式为 x[i] - x[j] <= a[k] (0 <= i, j < n, 0 <= k < m, a[k]已知),求 x[i] - x[j] 的最大值。
    例如当n = 4,m = 5,给出如下图所示的不等式组,求x3 - x0的最大值。
                                                  
    一般思路:我们可以尝试把几个不等式组合得到最后我们要求的式子,于是这些式子里最小的(因为要同时满足这三个条件,然后取最大的)那个就是答案。
    比如,在这个例子中:
    (3) ==》  x3 - x0<=4;
    (1)、(4)、(5) ==》 x3 - x0<=5;
    (2)、(5) ==》 x3 - x0<=3;
    所以最后结果就是3.
    在这个过程中,我们是否想到这种方法与我们已经学的一种算法有所联系,是的,就是最短路算法。
     

    三、差分约束与最短路模型

     

    1、与最短路模型的联系

     

    先给出结论:求解差分约束系统,都可以转化成图论的单源最短路径(或最长路径)问题。

    我们观察上面例子中的不等式,都是x[i] - x[j] <= a[k],可以进行移项,成为x[i] <= x[j] + a[k],我们令a[k] = w(j, i),dis[i]=x[i],并使i=v,j=u,那么原始就变为:dis[u]+w(u,v)>=dis[v],于是可以联想到最短路模型中的一部分代码

    if(dis[u]+w(u,v)<=dis[v])
    {
        dis[v]=dis[u]+w(u,v);
    }

    这不正与松弛操作相似吗?

    但是好像不等号方向刚好相反,但其实这并不矛盾

    2.问题解的存在性

     

        由于在求解最短路时会出现存在负环或者终点根本不可达的情况,在求解差分约束问题时同样存在

        (1)、存在负环

     

    如果路径中出现负环,就表示最短路可以无限小,即不存在最短路,那么在不等式上的表现即X[n-1] - X[0] <= T中的T无限小,得出的结论就是 X[n-1] - X[0]的最大值不存在。在SPFA实现过程中体现为某一点的入队次数大于节点数。(貌似可以用sqrt(num_node)来代替减少运行时间)

         (2)、终点不可达

    这种情况表明X[n-1]和X[0]之间没有约束关系,X[n-1] - X[0]的最大值无限大,即X[n-1]和X[0]的取值有无限多种。在代码实现过程中体现为dis[n-1]=INF。

    3、不等式组的转化

     

    做题时可能会遇到不等式中的符号不相同的情况,但我们可以对它们进行适当的转化

    (1)方程给出:X[n-1]-X[0]>=T ,可以进行移项转化为: X[0]-X[n-1]<=-T。

    (2)方程给出:X[n-1]-X[0]<T, 可以转化为X[n-1]-X[0]<=T-1。

    (3)方程给出:X[n-1]-X[0]=T,可以转化为X[n-1]-X[0]<=T&&X[n-1]-X[0]>=T,再利用(1)进行转化即可

    4、应用

    对于不同的题目,给出的条件都不一样,我们首先需要关注问题是什么,如果需要求的是两个变量差的最大值,那么需要将所有不等式转变成"<="的形式,建图后求最短路;相反,如果需要求的是两个变量差的最小值,那么需要将所有不等式转化成">=",建图后求最长路

    求最大值: 对于不等式 x[i] - x[j] <= a[k],对结点 j 和 i 建立一条 j -> i的有向边,求最短路

    求最小值: 对于不等式x[i] - x[j] >= a[k],对结点 j 和 i 建立一条 j -> i的有向边,求最长路

     

    如果图不连通,则在spfa开始时,把所有的结点放进队列,如下代码

    无论求最大还是求最小 都这样写

        for(int i=0; i<=n; i++)
        {
            Q.push(i);
            d[i] = 0;
            vis[i] = 1;
        }

    注意下界

    注意隐含条件,一般都是相邻的两个点之间 i 和 i + 1

    如果每个点都有个范围 则 设一个源点n + 1

    ZOJ 4028为例

    l <= a[i] <= r

    则 l <= a[i] - a[n - 1] <= r

    存在负环的话是无解 
     求不出最短路

    (1、dist[ ]没有得到更新 (先判断是否有负环 再判断能否求出最短路 即是否为任意解  再输出正解

            if(spfa()) printf("无解
    ");
            else if(d[n] == INF)
                printf("任意解
    ");
            else
            {
                printf("%d
    ", d[n]);
            }

    ),

    2、也可以把每条边减去INF 判断是否形成负环,这样还不形成负环的话就是任意解

    先判断是否有负环  再输出正解  再判断是否任意解

            bool flag = spfa();
            if(flag) printf("无解
    ");    
            else if(!flag && d[n] != INF)    //在这一步还要用d[n]与INF作比较  所以不如直接用第一种方法判定 
            {
                printf("%d
    ", d[n]);    
            }
            else if(!check(INF))
                printf("任意解
    ");

    )的话是任意解 。

    注意要求的东西

    典型题目:

    HDU - 1384 

    HDU - 1384 

    HDU - 1531

    HDU - 3666 

    总结一下:

      做差分约束一定要找个不等式关系,一般都有两个未知变量,像hdu1384  求的是与这个区间重合的元素,那我们就可以转化为sum(a)表示0到a区间与答案集合重合的元素

    然后sum(b) - sum(a - 1) >= w 或者 <= w 是不是就可以了  sum(a) 和 sum(b) 分别用a 和 b来表示就可以了

      像hdu 3666 有乘积的不等式 一定要想到log一下那么log(a) 和 log(b) 就可以分别用行和列来表示

    摘自:https://blog.csdn.net/my_sunshine26/article/details/72849441

    自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
  • 相关阅读:
    Sharding-JDBC多数据源动态切换
    U 盘安装 CentOS 7 时出现 No Caching mode page found 问题的解决
    sudo 密码直接添加到命令行以方便实现脚本自动化
    Python3 Windows 虚拟环境的若干问题
    20 张图让你彻底弄懂 HTTPS 原理!
    全网写得最好的分库分表之 Sharding-JDBC 中间件介绍
    以为线程池很简单,结果第一道题就被干趴下了!
    以为线程池很简单,没想到第一问就被干趴下了
    分布式事务,看这篇就够了!
    我是一个线程池
  • 原文地址:https://www.cnblogs.com/WTSRUVF/p/9153758.html
Copyright © 2020-2023  润新知