整理的算法模板合集: ACM模板


题目列表:

题目 算法
AcWing 1169. 糖果 差分约束系统、超级源点、求最值
UVA1723 Intervals 差分约束、求最值
AcWing 1170. 排队布局 差分约束
AcWing 393. 雇佣收银员 差分约束

差分约束系统

给出 n 个变量和 m 个约束条件,形如 xi−xj≤ckx_i - x_j \leq c_kxi​−xj​≤ck​,你需要求出一组解,使得所有约束条件均被满足。
怎样解这个差分约束系统呢?我们将上面的不等式变形一下:xi≤xj+ckx_i \leq x_j + c_kxi​≤xj​+ck​
容易发现这个形式和最短路中的三角形不等式 disv≤disu+wdis_v \leq dis_u + wdisv​≤disu​+w非常相似。
因此我们就将这个问题转化为一个求最短路的问题:比如对于上面这个不等式,我们从 j 向 i 连一条权值为 ckc_kck​的边。接下来,我们再新建一个 0 号点,从 0 号点向其他所有点连一条权值为 0 的边。这个操作相当于新增了一个变量 x0x_0x0​和 n 个约束条件:xi≤x0x_i \leq x_0xi​≤x0​,从而将所有变量都和 x0x_0x0​这一个变量联系起来。
然后以 0 号点为起点,用 spfa 跑最短路。如果有负权环,差分约束系统无解。否则设从 0 号点到 i 号点的最短路为 disidis_idisi​,则 xi=disix_i = dis_ixi​=disi​即为差分约束系统的一组可行解。

如上图,该图存在负环,如果一直沿着负环走,最短路径将会越来越小,最后到达−∞-∞−∞。
而此时的不等式就会出现矛盾,也就以为着没有正确的解

常用技巧

很多时候差分约束的条件并不是简单的小于等于号,这时候我们需要稍微做点变形。

  • 如果有 xi−xj≥ckx_i - x_j \geq c_kxi​−xj​≥ck​,则可以两边同时乘 −1,将不等号反转过来。

  • 如果有 xi−xj=ckx_i - x_j = c_kxi​−xj​=ck​,则可以把这个等式拆分为 xi−xj≤ckx_i - x_j \leq c_kxi​−xj​≤ck​和 xi−xj≥ckx_i - x_j \geq c_kxi​−xj​≥ck​两个约束条件,如果要求的是最值问题,那么我们应该统一符号,A=BA = BA=B 改成 A>=B,B>=AA>= B,B>= AA>=B,B>=A。

  • 求最值通用(一定要用)的不等式:si≥si+1s_i≥s_{i + 1}si​≥si+1​ / si≤si+1s_i≤s_{i + 1}si​≤si+1​(有时可以用si≥0s_i≥0si​≥0)

注意超级虚拟源点的假设;差分条件一定要找全;变量的绝对值不能忘;

y总上课的截图:

有负环就不存在最短路
存在负环则会矛盾

原不等式无解等价于有负环
最短路
xi<=xj+ck;x_i <= x_j + c_k;xi​<=xj​+ck​;
dist[i]<=dist[j]+ck;dist[i] <= dist[j] + c_k;dist[i]<=dist[j]+ck​;
从j到i连权值为c_k的边

最长路
xj>=xi−ck;x_j >= x_i - c_k;xj​>=xi​−ck​;
dist[j]>=dist[i]+ck;dist[j] >= dist[i] + c_k;dist[j]>=dist[i]+ck​;
从j到i连权值为-c_k的边

最大值:所有的上界中找最小的即为答案->最短路

{x <= 5
{x <= 3
{x <= 2
->x = 2

最小值:所有的下界中找最大的即为答案->最长路
求最大值最小值问题,必须有一个边界条件;
例如求最小值,要求最长路,要设置xi<=0x_i<=0xi​<=0
不然根据方程只能求得各各x_i的相对关系,没办法求得最终的最值
比如我们给定xi<=0x_i<=0xi​<=0
转换成边:
建立一个超级源点0,x0=0x_0 = 0x0​=0,这样既是从0到i连一个权值为0的边
转换成xi<=x0+0;x_i <= x_0 + 0;xi​<=x0​+0;

例题

差分约束的题写起来非常简单,关键是通过读题找到各种不等式以及一些边界,建图,然后直接跑一个最短路即可

A、AcWing 1169. 糖果(差分约束系统、超级源点)

这里求的是至少,也就是最小值->下界中找最大->最长路

根据题意我们由于要求最长路,因此我们应该全部转换成大于号,我们如下图做下列更改


由于我们要求的是最值,单是有这些题目中已知的式子我们只能得到每一个x之间的相对关系,并没有一个边界,是无法求出最值的。根据题意,我们知道每一个小朋友至少有一个糖果,所以我们得到了一个边界:x>=1x >= 1x>=1,转换成最长路的形式既是:x>=x0+1x >= x_0 + 1x>=x0​+1,这里的x0x_0x0​是我们的老朋友超级源点,这里是 000。
然后按照上面的式子建图跑最短路即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstring>using namespace std;
typedef long long ll;const int N = 1e6 + 7, M = 1e7 + 7,INF = 0x3f3f3f3f;
int ver[M],nex[M],edge[M],head[N],tot = 1;
int n,m,k;
int cnt[N];
int dist[N];
bool vis[N];
int q[M];
void add(int x,int y,int z){ver[++tot] = y;edge[tot] = z;nex[tot] = head[x];head[x] = tot;
}bool spfa(){//最长路memset(dist,0xcf,sizeof dist);int hh = 0,tt = 0;q[tt ++ ] = 0;dist[0] = 0;vis[0] = true;while(hh != tt){int x = q[-- tt];vis[x] = false;for(int i = head[x];i;i = nex[i]){int y = ver[i],z = edge[i];if(dist[y] < dist[x] + z){dist[y] = dist[x] + z;cnt[y] = cnt[x] + 1;if(cnt[y] > n)return false;if(!vis[y]){vis[y] = true;q[tt ++ ] = y;}}}}return true;
}int main(){scanf("%d%d",&n,&k);for(int i = 1;i <= k;++i){int x,a,b;scanf("%d%d%d",&x,&a,&b);if(x == 1)add(b,a,0),add(a,b,0);else if(x == 2)add(a,b,1);else if(x == 3)add(b,a,0);else if(x == 4)add(b,a,1);else add(a,b,0);}for(int i = 1;i <= n;++i)add(0,i,1);ll ans = 0;if(!spfa())puts("-1");else {for(int i = 1;i <= n;++i)ans += dist[i];cout<<ans<<endl;}return 0;
}

B、UVA1723 Intervals(差分约束)


本题的题意就是从000 ~ 500005000050000中选出尽量少的整数,使得每一个区间[ai,bi][a_i,b_i][ai​,bi​]内都至少有cic_ici​个整数

那么我们设s[k]s[k]s[k]表示的是000 ~ kkk之间最少选取多少个整数,则根据题意,有s[bi]−s[ai−1]≥cis[b_i]-s[a_i - 1]\geq c_is[bi​]−s[ai​−1]≥ci​

另外由于我们要求的是求最值,因此仅有这一个相对关系式是无法求得最值的。根据经验我们可以考虑sis_isi​和si−1s_{i-1}si−1​之间的关系。
很明显si≥si−1s_i\geq s_{i-1}si​≥si−1​既是si−si−1≥0s_i-s_{i-1} \geq 0si​−si−1​≥0
以及si−si−1≤1s_i-s_{i-1} ≤ 1si​−si−1​≤1(每一个数只能选一次),由于我们求的是最小值->下界最大->最长路,因此我们应该把符号全部换成≥\geq≥,所以上式可以变形为si−1−si≥−1s_{i-1}-s_i \geq -1si−1​−si​≥−1

{s[bi]−s[ai−1]≥cis[i]−s[i−1]≥0s[i−1]−s[i]≥−1\left\{ \begin{aligned} \ \ \ \ \ \ \ \ \ \ s[b_i]-s[a_i - 1]\geq c_i \\s[i]-s[i - 1] \geq 0 \\ \ \ \ \ \ s[ i - 1 ] - s[i] \geq -1\\ \end{aligned} \right. ⎩⎪⎨⎪⎧​          s[bi​]−s[ai​−1]≥ci​s[i]−s[i−1]≥0     s[i−1]−s[i]≥−1​

我们需要找到一个源点,满足该源点可以到达所有的边,易证可以以 000 为源点,建图:
s[i−1]−s[i]≥−1s[ i - 1 ] - s[i] \geq -1s[i−1]−s[i]≥−1从所有的 i−1i-1i−1 到 iii 连权值为 000 的有向边、
s[i−1]−s[i]≥−1s[ i - 1 ] - s[i] \geq -1s[i−1]−s[i]≥−1 从所有的i到i-1连权值为-1的有向边、
s[bi]−s[ai−1]≥cis[b_i]-s[a_i - 1]\geq c_is[bi​]−s[ai​−1]≥ci​从每一个ai−1a_i- 1ai​−1到bib_ibi​连权值为cic_ici​的有向边。
由于a和b的数据范围为000 ~ 500005000050000,而我们的源点为0,因此我们输入的时候将a和b都++,将数据范围改成111 ~ 500015000150001。再以0为源点跑一个最长路即可。

由于本题保证ci≤bi−ai+1c_i≤b_i -a_i+1ci​≤bi​−ai​+1,所以图中是没有正环的,差分约束系统一定有解。我们输入a和b的时候求一下b的最大值maxx,最后求完最长路以后答案就是dist[maxx]dist[maxx]dist[maxx](dist[maxx]dist[maxx]dist[maxx]是所有下界的最大值)

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstring>using namespace std;
typedef long long ll;const int N = 5e5 + 7, M = 5e6 + 7,INF = 0x3f3f3f3f;void read(int &x)
{int f=1;x=0;char s=getchar();while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}x*=f;
}int n,m;
int ver[M],nex[M],edge[M],head[N],tot = 1;
int dist[N];
bool vis[N];
int q[N];void add(int x,int y,int z){ver[ ++ tot] = y;edge[tot] = z;nex[tot] = head[x];head[x] = tot;
}void spfa(){memset(dist,0xcf,sizeof dist);dist[0] = 0;vis[0] = true;int hh = 0,tt = 0;q[tt ++ ] = 0;while(hh != tt){int x = q[hh ++ ];if(hh == N)hh = 0;vis[x] = false;for(int i = head[x];i;i = nex[i]){int y = ver[i],z = edge[i];if(dist[y] < dist[x] + z){dist[y] = dist[x] + z;if(!vis[y]){q[tt ++ ] = y;if(tt == N)tt = 0;vis[y] = true;}}}}
}
int t;
int maxx;
int main(){memset(head,0,sizeof head);tot = 1;read(n);for(int i = 1;i <= n;++i){int a,b,c;read(a),read(b),read(c);a ++ ,b ++ ;add(a - 1,b,c);maxx = max(maxx,b);}for(int i = 1;i <= maxx;++i){add(i - 1,i,0);add(i,i - 1,-1);}spfa();printf("%d\n",dist[maxx]);return 0;
}

C、AcWing 1170. 排队布局

这里数据是排过序的。
这里有两种不等式关系,Ai−Bi≤CiA_i-B_i≤C_iAi​−Bi​≤Ci​,这种也就是从B向A连权值为C的边,另一种同理。

上面也写了,求最值一定要用的不等式:si≥si+1s_i≥s_{i + 1}si​≥si+1​ / si≤si+1s_i≤s_{i + 1}si​≤si+1​。本题不用的话就会被hack
这里si≥0s_i≥0si​≥0或者si≤0s_i≤0si​≤0都是成立的,因为我们这里没有给具体的坐标,只是让求相对距离,所以这两个不等式都是可以成立的。自己选择。这里由于我们求的是最大值->上界中找最小的->最短路-> ≤≤≤,因此我们应该选择si≤0s_i≤0si​≤0。然后开始分别连边。

根据题目要求先从0出发判断有无负环,若有负环输出-1
然后从1出发求一次,若dis[n]==INF则输出-2
1n的最大差值即为满足上述条件(满足所有上界)的图中的最短路dis[n]

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstring>using namespace std;
typedef long long ll;void read(int &x)
{int f=1;x=0;char s=getchar();while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}x*=f;
}
const int N = 5007;
const int M = 50007;
const int INF = 0x3f3f3f3f;
typedef pair<int,int> PII;int n,m;
int ver[M],edge[M],nex[M],head[N],tot;
int dis[N],cnt[N];
bool vis[N];void add(int x,int y,int z){ver[++tot] = y;edge[tot] = z;nex[tot] = head[x];head[x] = tot;
}bool spfa(int s){queue<int>q;memset(vis,0,sizeof vis);memset(dis,0x3f,sizeof dis);memset(cnt,0,sizeof cnt);dis[s] = 0;q.push(s);vis[s] = true;while(q.size()){int x = q.front();q.pop();vis[x] = 0;for(int i = head[x];i;i = nex[i]){int y = ver[i],z = edge[i];if(dis[y] > dis[x] + z){dis[y] = dis[x] + z;cnt[y] = cnt[x] + 1;if(cnt[y] >= n)return false;if(!vis[y]){vis[y] = 1;q.push(y);}}}}return true;
}
int o;
int main(){scanf("%d%d%d",&n,&m,&o);for(int i = 1;i <= n;++i)//建超级源点add(0,i,0);for(int i = 1;i <= n;++i)add(i +1,i,0);for(int i = 1;i <= m;++i){int x,y,z;scanf("%d%d%d",&x,&y,&z);add(x,y,z);//xi - xj ≤ k//j来更新i,所以j向i连一条权值为k的边}for(int i = 1;i <= o;++i){int x,y,z;scanf("%d%d%d",&x,&y,&z);add(y,x,-z);}if(!spfa(n))puts("-1");else {spfa(1);if(dis[n] == INF)puts("-2");else cout<<dis[n]<<endl;}return 0;
}

【图论专题】差分约束系统相关推荐

  1. 图论 —— 差分约束系统

    [概述] 如果一个系统由 n 个变量 m 个约束条件组成,形成 m 个形如  的不等式,其中 ,k 是常数,则称这 m 个不等式为差分约束系统(system of difference constra ...

  2. 图论--差分约束系统

    先上一张图,看懂了就可以走了!你学会了! 求x1-x4的最大值,由题目给的式子1,2,4可得x1-x4>=11,我们来看图中最短路,x1到X4的最短距离也是11,也就是说差分约束系统就是将给定条 ...

  3. 提高篇 第三部分 图论 第4章 差分约束系统

    差分约束系统_我的ACM,我的梦!!!-CSDN博客_差分约束系统 差分约束系统详解 - hr_whisper - 博客园 最短路径算法:Bellman和差分约束系统_算法导论视频课程_其他视频-51 ...

  4. 差分约束系统——建模与求解

    如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如:xj-xi<=bk,其中,1<=i,j<=n, 1<=k<=m.则称其为差分约束系统(System of ...

  5. 【转】 差分约束系统详解(转化为最短路) (概念)

    ---恢复内容开始--- 转自:http://www.cnblogs.com/void/archive/2011/08/26/2153928.html 差分约束系统中: 如果求未知数的最大值,那么按小 ...

  6. 图论专题1(网络流)

    推荐阅读: 网络流基础知识和Dinic:http://www.cnblogs.com/SYCstudio/p/7260613.html#3848907 建模:https://www.cnblogs.c ...

  7. 【图论专题】拓扑排序

    拓扑排序 给定一张有向无环图,若一个序列A满足图中的任意一条边(x,y)x都在y的前面呢么序列A就是图的拓扑排序 实际上拓扑排序就是满足所有的边x指向y,x一定在y的前面.这样按照拓扑排序递推,就可以 ...

  8. 差分约束系统【模板】

    差分约束系统:如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如 xj - xi<= bk ( i , j ∈ [1,n],k ∈ [1,m]),则称其为差分约束系统.  例如如下的 ...

  9. POJ 1364 King (差分约束系统)

    题目描述有点复杂,前面讲了一大堆废话. 题目大意:对一个含n个整数的序列进行一些约束: 1.整数序列中连续的一段的和大于某个整数: 2.整数序列中连续的一段的和小于某个整数. 问满足以上约束的整数序列 ...

最新文章

  1. H5 Canvas刮刮乐
  2. 每天一道LeetCode-----实现LRU置换算法
  3. 谷歌浏览器打开标签会把之前的覆盖掉_Chrome 浏览器新更新解决了本地文件拖入导致的标签页意外关闭问题...
  4. Mybatis自学日志02
  5. __attribute__((visibility(default)))
  6. c语言中int型变量的字节数
  7. java中map的使用和排序使用
  8. 深入理解HTTP协议—HTTP协议详解(真的很经典)
  9. 搜狗推出卫星影像地图 将覆盖全部七个奥运城市
  10. 离散数学 习题篇 —— 等价关系的计数
  11. 华为手机助手(PC)无法连接的通用解决方案
  12. 【税务基础知识】--很实用的常识
  13. Ubuntu安装bluefish2.0.最新版本方法
  14. Leetcode编程练习一:盗马三则
  15. 【网络实验】10G网络下的真实带宽——CPU负载与网卡TSO、GSO
  16. 计算机中丢失granny2,修复granny2.dll
  17. 幼儿园手工之自制时钟_「时钟手工」幼儿园玩教具手工时钟,培养孩子的时间观念...
  18. 第二章、小实例,画字,画线,矩形,画图,动画(iOS学习笔记,从零开始。)
  19. 【Web技术】1257- 基于FFmpeg的图片合成视频
  20. 高新技术企业认定申报书编制的要求是什么?

热门文章

  1. 实战:基于OpenCV实现偏斜文档校正
  2. 如何用 OpenCV、Python 和深度学习实现面部识别?
  3. 重磅升级,52个Python+OpenCV实战项目教你掌握图像处理
  4. C++——创建类的时候用new与不用new 的区别(转)
  5. Java 获取当前时间最近12个月(字符串)
  6. Laravel 中简约而不简单的 Macroable 宏指令
  7. UITableViewCell 左侧滑动删除按钮 添加图片 (不完美解决)
  8. 大型网站技术架构(3):WEB 前端性能优化
  9. 陶哲轩实分析 习题 7.5.2
  10. pythonslice_shift_3. 数据模型