图论学习-差分约束入门

差分约束

一、什么是差分约束?

求不等式组的可行解。

1.1 概念

差分约束系统是一种特殊的N元一次不等式组,它包含N个变量X1~Xn,以及M个约束条件,每个约束条件都是由两个变量作差构成的,形如
X i − X j < = C k ( C k 是 常 数 ) 注 : 必 须 是 形 如 上 式 这 样 的 形 式 如 果 不 是 , 需 要 转 化 成 上 式 X_i-X_j<=C_k(C_k是常数)\\注: \\必须是形如上式这样的形式\\如果不是,需要转化成上式 XiXj<=Ck(Ck)
需要解决的问题是:求一组解
X 1 = a 1 , X 2 = a 2 . . . 使 所 有 约 束 条 件 都 能 满 足 X_1 = a_1,X_2 = a_2...使所有约束条件都能满足 X1=a1,X2=a2...使

1.2 与图论的联系

对于差分约束系统的每个约束条件 X i − X j < = C k X_i-X_j<=C_k XiXj<=Ck都可以变形为 X i < = X j + C k X_i<=X_j+C_k Xi<=Xj+Ck

而它与最短路问题中的三角形不等式dist[y]<=dist[x]+z相似
所以可以把所有形如
X i < = X j + C k X_i<=X_j+C_k Xi<=Xj+Ck
的式子看成是从 j 出发向 i 连一条长度为C_k的有向边
那么可以注意到:求解该不等式组的解就是对这个不等式所建的图求最短路径。
在这里插入图片描述
所以求差分约束的解的问题等价于求最短路的问题。

1.3 成立条件

对于求单源最短路问题,
源点需要满足条件:从源点出发,一定可以走到所有的边。需要找一个可以走到所有边的源点。

1.4 解题步骤

  1. 先将每个不等式 x i < = x j + c x_i<=x_j+c xi<=xj+c转化为一条从 j 走到 i ,长度为c的一条边
  2. 找一个超级源点(或者建立一个虚拟源点),使得该源点一定可以遍历到所有边
  3. 从源点求一遍单源最短路
    结果1:如果存在负环,则原不等式组一定无解,详见1.5
    结果2:如果没有负环,则dist[i]就是原不等式组的一个可行解。

1.5 特殊情况

如果图存在负环,比如下图的环是负环:
在这里插入图片描述
先观察图,易有:
x 2 < = x 1 + c 1 . . . . . . ( 1 ) x 3 < = x 2 + c 2 . . . . . . ( 2 ) . . . x k − 1 < = x k − 2 + c k − 2 . . . . . . ( k − 2 ) x k < = x k − 1 + c k − 1 . . . . . . ( k − 1 ) x 1 < = x k + c k . . . . . . ( k ) x_2<=x_1+c_1......(1)\\ x_3<=x_2+c_2......(2)\\ ...\\ x_{k-1}<=x_{k-2}+c_{k-2}......(k-2)\\ x_k<=x_{k-1}+c_{k-1}......(k-1)\\ x_1<=x_k+c_k......(k) x2<=x1+c1......(1)x3<=x2+c2......(2)...xk1<=xk2+ck2......(k2)xk<=xk1+ck1......(k1)x1<=xk+ck......(k)
观 察 易 有 x 2 < = x 1 + c 1 < = x k + c k + c 1 < = x 2 + c 1 + c 2 + c 3 + . . . + c k 而 因 为 是 负 环 , 则 c 1 + c 2 + c 3 + . . . + c k < 0 ∴ x 2 < = x 2 + ( 小 于 0 的 式 子 ) 显 然 矛 盾 ∴ 如 果 图 中 存 在 负 环 , 那 么 不 等 式 组 一 定 存 在 矛 盾 , 无 解 。 观察易有 x_2<=x_1+c_1<=x_k+c_k+c_1\\<=x_2+c_1+c_2+c_3+...+c_k \\而因为是负环,则c_1+c_2+c_3+...+c_k<0\\ \therefore x2<=x2+(小于0的式子) 显然矛盾\\ \therefore 如果图中存在负环,那么不等式组一定存在矛盾,无解。 x2<=x1+c1<=xk+ck+c1<=x2+c1+c2+c3+...+ckc1+c2+c3+...+ck<0x2<=x2+(0)

1.6 如何求最大值或者最小值

这里的最值指的是对于每个变量在满足约束条件情况下所能取得的最值。
结论:如果求的是最小值,则应该求最长路,如果求的是最大值,则应该求最短路。
问题1: 如何转化xi<=c? 建立一个超级源点:0,然后建立0->i,长度为c的边即可。

二、例题

题目1:P3275 [SCOI2011]糖果

链接
分析:
在这里插入图片描述
随后根据不等式建图,
ac code:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll N = 2e6+10,M = N;
ll h[N], e[M], ne[M], w[M],idx;
ll dist[N],q[N],cnt[N];
bool st[N];
void add(ll a, ll b, ll c)  // 添加一条边a->b,边权为c
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
ll n,m;

bool spfa()
{
   memset(dist,-0x3f,sizeof dist);//因为是求最长路
   int hh = 0,tt = 1;
   dist[0] = 0;
   q[0] = 0;
   st[0] = true;
   while(hh<=tt)
   {
       auto t = q[--tt];
       st[t] = false;
       for(int i = h[t];~i;i = ne[i])
       {
           int j = e[i];
           if(dist[j]<dist[t]+w[i])
           {
               dist[j] = dist[t]+w[i];
               cnt[j] = cnt[t]+1;
               if(cnt[j]>=n+1) return false;
               if(!st[j])
               {
                   q[tt++] = j;
                   st[j] = true;
               }
           }
       }
   }
   return true;
}
int main()
{
    memset(h, -1, sizeof h);
    memset(st, 0, sizeof st);
    cin>>n>>m;
    while (m -- ){
        ll x,a,b;
        cin>>x>>a>>b;
        if (x == 1) add(b, a, 0), add(a, b, 0);//A=B
        else if (x == 2) add(a, b, 1);//B≥A+1
        else if (x == 3) add(b, a, 0);//A≥B
        else if (x == 4) add(b, a, 1);//A≥B+1
        else add(a, b, 0);
    }
    for(ll i = 1;i<=n;i++) add(0,i,1);
    bool t = spfa();
    if(!t)
    {
        cout<<"-1";
        return 0;
    }
    ll res = 0;
    for(ll i = 1;i<=n;i++)
    {
        res+=dist[i];
    }
    cout<<res;
    //求最小值,用最长路
    return 0;
}

后续更新~

题目2:

  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值