差分约束算法

本文介绍了差分约束系统的基本概念,如何将不等式转化为图的边,以及如何通过求解单源最短路来判断不等式是否存在可行解。在求解最大值或最小值时,可以通过求最长路或最短路来实现。举例说明了如何应用这些方法解决实际问题,例如幼儿园糖果分配问题,将其转换为不等式并求解。
摘要由CSDN通过智能技术生成

概括

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

求不等式的可行解

源点需要满足的条件: 从源点出发,一定可以走到所有的边
否则 用单源最短路做的话 有一条边走不到 则该边对应的不等式就无法满足

  1. 把每个x[i] ≤ x[j] + C[k]不等式转化为一条从 x[j] 走到 x[i] 长度为 C[k] 的边

  2. 然后在这个图上找一个超级源点,使得该源点一定可以遍历到所有边

  3. 从源点求一遍单源最短路
    3.1假如存在负环

    x[2] ≤ x[1] + c[1]

    x[k] ≤ x[k-1] + c[k-1]
    x[1] ≤ x[k] + c[k]
    对第一个不等式用后面的不等式一直做松弛
    x[2] ≤ x[1]+c[1]
        ≤ x[k] + c[k] + c[1]
        ≤ x[k-1] + c[k-1] + c[k] + c[1]
       …
        ≤ x[2] + c[2] +…+ c[k-1] + c[k] + c[1]
        ≤ x[2] + (小于零的Σc[i])
    x[2] < x[2]

    矛盾

    得出结论:不等式无解 即存在负环

4.求完单源最短路之后
 存在负环 => 不等式无解
 没有负环 => 求完之后一定是满足这个不等式的 <=> 即一个可行解

求最大值或最小值

结论 : 如果求的是最小值,则应该求最长路,如果求的是最大值,则应该求最短路

问题 : 如何转化 x[i] ≤ c (其中 c 是一个常数) 这类的不等式
方法 : 建立一个超级源点, 0 号点 x[0] ,然后建立 0→i 长度是 c 的边即可

x[i] ≤ c <=> x[i] ≤ x[0] + c = 0 + c

以求 x[i] 的最大值为例:所有从 x[i] 出发,构成的不等式链

x[i] ≤ x[j] + c[1] ≤ x[k] + c[2] + c[1] ≤⋅⋅⋅≤ x[0] + c[1] + c[2] +⋅⋅⋅+ c[m] (x0=0)

所计算出的上界,最终 x[i] 的最大值 = 所有上界的最小值

那么求x[i]最大值

求所有上界的最小值

求所有从 0→i 的路径和的最小值

最短路求 dist[i]

例题

题目概括

幼儿园里有 N 个小朋友,老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。
但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候, 老师需要满足小朋友们的 K 个要求。
幼儿园的糖果总是有限的,老师想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。

输入

输入的第一行是两个整数 N,K。
接下来 K 行,表示分配糖果时需要满足的关系,每行 3 个数字 X,A,B。
如果 X=1.表示第 A 个小朋友分到的糖果必须和第 B 个小朋友分到的糖果一样多。
如果 X=2,表示第 A 个小朋友分到的糖果必须少于第 B 个小朋友分到的糖果。
如果 X=3,表示第 A 个小朋友分到的糖果必须不少于第 B 个小朋友分到的糖果。
如果 X=4,表示第 A 个小朋友分到的糖果必须多于第 B 个小朋友分到的糖果。
如果 X=5,表示第 A 个小朋友分到的糖果必须不多于第 B 个小朋友分到的糖果。
小朋友编号从 1 到 N。

输出

输出一行,表示老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出 −1。

由题我们可以转换成不等式

  1. A = B <=> A≥B B≥A
  2. A < B <=> B≥A+1
  3. A≥B <=> A≥B
  4. A > B <=> A≥B+1
  5. B≥A <=> B≥A

每个人都能够分到糖果所以可以得到 x ≥ 1

x ≥ x0 + 1 可以设源点 x0 = 0

代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

typedef long long LL;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值