一、前言

在介绍差分约束之前,我们首先需要知道差分约束是用来解决什么问题的:差分约束是一个用来解决形如 X<=Y+c 的二元不等式组的可行解的一个算法。在高中数学中我们会学习如何使用线性规划的方法来解决这个问题来求出不等式的可行解或者最大最小解。而在ACM中,差分约束算法可以将求解不等式组的问题转化为图论问题,通过图论中的知识来解决。

二、差分约束

1.求不等式组可行解的前提条件

  • 将每一个未知数转化为图论上的一个点,根据不等式组建立一个有向图(建立有向图的具体方法将在后文中提及)
  • 建立一个虚拟超级原点,从该原点出发可以到达有向图中的每一条边,一般建立一个原点,该点到每一个点都有一条长度为0的有向边。
  • 对于每一个未知数X,从原点出发到X的距离就是X的一个满足条件的可行解。

2.算法步骤

  • 先根据原不等式组建立有向图(建图的方法将在后文提及)
  • 建立一个超级源点
  • 使用SPFA算法从源点求单源最短(长)路
    • 结果1:有向图存在负环,不等式无解
    • 结果2:没有负环,dis[i] 就是原不等式组的一个可行解

注意:
1.图中存在点在求最短(最长)路后的距离仍然为INF(-INF),代表该未知数的取值不受任何约束,可以取任意值。
2.在实际解题时一定要找准找全题目中所有的不等式约束关系

3.建立有向图

1)求最大可行解
  • 最大可行解:所有的可行解中某个未知数X的值最大
  • 未知数X的最大可行解为:从超级源点到点X的最短路dis[x]
  • 有向图建立方法:
    • 将所有的不等式转化为X <= Y + c 的形式
    • 建立有向边Y-->X,长度为c
    • 注意一定是<=,如果是X < Y可以转化为X <= Y - 1
    • 如果存在不等式形如c <= Y,转化为X0 <= Y - c,X0为超级源点。
2)求最小可行解
  • 最小可行解:所有的可行解中某个未知数X的值最小
  • 未知数X的最小可行解为:从超级源点到点X的最长路dis[x]
  • 有向图建立方法:
    • 将所有的不等式转化为X + c <= Y 的形式
    • 建立有向边X-->Y,长度为c
    • 注意一定是<=,如果是X < Y可以转化为X + 1 <= Y
    • 如果存在不等式形如Y <= c,转化为Y - c <= X0,X0为超级源点。
3)证明
  • 以求xi的最大值为例:求从xi出发,构成的不等式链xi <= xj + c1 <= xk + c1 +c2 <= ...... <= c1+c2+c3+...+cn,求出来的上界的最小值就是可行解的最大值。

代码(结合例题)

糖果幼儿园里有 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≤N<1e5,
1≤K≤1e5,
1≤X≤5,
1≤A,B≤N
输入样例:
5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1
输出样例:
11

正确代码

// Problem: 糖果
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1171/
// Memory Limit: 64 MB
// Time Limit: 1000 ms//#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl '\n'
#define fi first
#define se second
#define pb push_back
#define int long long
#define INF 0x3f3f3f3f
#define ull unsigned long long
#define print(x) cout << (x) << endl
#define all(x) (x).begin(), (x).end()
#define mem(a, b) memset(a, b, sizeof(a))
#define f(i, l, r) for (int i = (l); i <= (r); i++)
#define ff(i, l, r) for (int i = (l); i >= (r); i--)
#define pr(x, n) f(_, 1, n) cout << (x[_]) << " \n"[_ == n];
#define ck(x) cerr << #x << "=" << x << '\n';
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 7, mod = 1e9 + 7;int n, k;
int h[N], e[N], ne[N], v[N], id;
int dis[N];
int cnt[N];
bool in_st[N];void add(int a, int b, int c)
{ne[id] = h[a], h[a] = id, e[id] = b, v[id++] = c;
}bool spfa()
{mem(dis, -0x3f);stack<int> st;dis[0] = 0;st.push(0);in_st[0] = true;while (st.size()){int te = st.top();st.pop();in_st[te] = false;for (int i = h[te]; ~i; i = ne[i]){int j = e[i];if (dis[j] < dis[te] + v[i]){dis[j] = dis[te] + v[i];cnt[j] = cnt[te] + 1;if (cnt[j] > n){return false;}if (!in_st[j]){st.push(j);in_st[j] = true;}}}}return true;
}void solve()
{mem(h, -1);cin >> n >> k;f(i, 1, n){add(0, i, 1);}while (k--){int a, b, op;cin >> op >> a >> b;if (op == 1)add(a, b, 0), add(b, a, 0);else if (op == 2)add(a, b, 1);else if (op == 3)add(b, a, 0);else if (op == 4)add(b, a, 1);elseadd(a, b, 0);}if (spfa()){int ans = 0;f(i, 1, n) ans += dis[i];print(ans);}elseprint(-1);
}signed main()
{std::ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);clock_t start_time = clock();int __ = 1;//    cin>>__;//    init();while (__--)solve();clock_t end_time = clock();// cerr << "Running time is: " << ( double )(end_time - start_time) / CLOCKS_PER_SEC * 1000 << "ms" << endl;return 0;
}

作者:Avalon·Demerzel
更多文章详见专栏:图论与数据结构

【图论】差分约束算法详解相关推荐

  1. 图论:SPFA 算法详解( 算法竞赛入门到进阶) HDU 2544 链式前向星 【提供ACM模板+图解,不会都难!】

    文章目录 SPFA简介 链式前向星介绍 SPFA算法思路详细 模板-链式前向星 参考书籍:算法竞赛入门到进阶 罗勇军 SPFA简介 用队列处理Bellman-Ford算法可以很好地优化,这种方法叫做S ...

  2. 图论-最短路Dijkstra算法详解超详 有图解

    整体来看dij就是从起点开始扩散致整个图的过程,为什么说他稳定呢,是因为他每次迭代,都能得到至少一个结点的最短路.(不像SPFA,玄学复杂度) 但是他的缺点就是不能处理带负权值的边,和代码量稍稍复杂. ...

  3. 图论2-SAT算法详解

    图论2-SAT算法详解 今天我们来介绍一个我个人认为最难的算法,这是为什么呢?肯定会有许多dalao说,不就一个2-SAT,我两分钟就A掉了.然而2-SAT的细节非常的多,稍不注意就会写错,而且测试困 ...

  4. SIFT特征点提取及描述论文算法详解

    SIFT特征点提取及描述论文算法详解 1. 尺度空间极值检测(Scale-space extrema detection) 1.1 尺度空间和极值 1.2 DoG和LoG的关系 1.3 构建高斯尺度差 ...

  5. 谱聚类算法详解及代码实现

    谱聚类算法详解及代码实现 文章目录 谱聚类算法详解及代码实现 参考 关于谱聚类介绍 谱聚类概述 谱聚类前置知识 无向权重图 邻接矩阵 度矩阵 拉普拉斯矩阵 相似度矩阵 确定目标函数 初始化目标函数(最 ...

  6. 解题报告:P5960 【模板】差分约束算法(及常用技巧)

    P5960 [模板]差分约束算法 差分约束系统 给出 n 个变量和 m 个约束条件,形如 xi−xj≤ckx_i - x_j \leq c_kxi​−xj​≤ck​,你需要求出一组解,使得所有约束条件 ...

  7. Union-Find 并查集算法详解

    Union-Find 并查集算法详解 文章目录 Union-Find 并查集算法详解 一.问题介绍 二.基本思路 三.平衡性优化 四.路径压缩 五.总结 六.例题 一.问题介绍 简单说,动态连通性其实 ...

  8. 【模板】差分约束算法

    [模板]差分约束算法 题意: 题解: 模板题 算法讲解 给出一组包含 m 个不等式,有 n 个未知数.求任意一组满足这个不等式组的解,或判定无解. 连边之后跑最短路,保证每个连通块都没有负环即可. 也 ...

  9. 离线强化学习(Offline RL)系列3: (算法篇) IQL(Implicit Q-learning)算法详解与实现

    [更新记录] 论文信息:Ilya Kostrikov, Ashvin Nair, Sergey Levine: "Offline Reinforcement Learning with Im ...

最新文章

  1. 上课讲到的设计模式总结
  2. 12CSS中的盒子模型
  3. 开发日记-20190915 关键词 汇编语言王爽版 第十章
  4. KnockoutJS 3.X API 第一章 简介
  5. 查找字符串中首个非重复字符
  6. OpenCV:Surface Matching 3D
  7. Java——多线程(死锁)
  8. Spring笔记——数据源配置
  9. python里的define怎么用_如何用(?(DEFINE))在Python中编写正则表达式?
  10. 【干货下载】2020新基建展望:新战略、新动力、新格局.pdf(附下载链接)
  11. java 线程map_map集合分割以及多线程处理数据
  12. JAVA中解决Filter过滤掉css,js,图片文件等问题
  13. linux学习命令总结⑩⑦
  14. 《Java程序设计精编教程(第3版)》之课后习题 - 个人作
  15. Python之灵异事件
  16. 小众骑行路线-十里箐
  17. 10.5亿人次观看珠海航展!图扑助力展商数字孪生演示,太震撼!
  18. 液晶屏背光板的分类及知识点
  19. 全国计算机大赛特等奖,我校学子获中国高校计算机大赛网络技术挑战赛特等奖...
  20. 《CSDN云原生工程师能力认证——IT人才进名企的牵引者》

热门文章

  1. 数据挖掘简单可视化方法
  2. 接入Apple 登录(AuthenticationServices) 后端处理Java版
  3. 探索性数据分析(EDA)
  4. 5G+工业互联网的中国登山队,如何攀跃“产业化”山峦?
  5. 幼儿园带括号算式口诀_幼儿园数学作业括号题型
  6. 硬币之谜:如何用最少的步骤拿完所有硬币?
  7. 通过循环引用问题来分析Spring源码
  8. 线上FGC调优案例三则
  9. JDBC概述(JDBC是什么,主要作用,驱动类型等)
  10. C++编译错误fatal error C1004: 发现意外的文件尾