[关闭]
@sztom 2019-08-14T13:20:03.000000Z 字数 3181 阅读 2204

浅谈差分约束系统

算法 图论九讲

by szTom

under group algorithm - graph


1.从代数到图论

1.1.差分约束方程

差分约束方程就是形如 方程组

比如说:

就是一组差分方程。
下面是它的一组解:

一组差分约束方程要么有无穷组解,要么无解。因为如果它有解,那么它的解同时加上一个实数 ,依旧是一组解。因为每个数都加,他们任意两个数之间的差是不变的,所以对于不等式没有影响。


上式的解还可以是

(同时加


1.2.图论解法

多数博客接下来是这么说的:

看到
有没有想到什么呢? 可以变形为 ,这与单元最短路中的三角形不等式非常相似

因此,可以把每个变量 看做有向图中的一个结点,对于约束条件 ,从结点向结点i连一条权值为 的有向边。

这里补充一下:就是上面的一组解。

讲得是没错,然而,凭什么长得像就可以随便乱套呢?

首先第一步最开始,
我们画张图看看:

e8SIDP.png

比如对于,如果有当前从1到3的最短路大于5,那么一定会被这条路()替换掉。

同理,对于 ,如果有当前从的最短路大于,那么一定会被这条路()替换掉。

大于也是同样的原理,可以举一反三。

同理可得其它边,以保证在前提(差分约束方程)不被违反的情况下得到最优解。

2.差分约束系统

2.1.大于还是小于

众所周知,不等式方程是互通的,它们可以互相转换。


刚才的方程组:

等价于:


那么差分约束系统该用大于还是小于呢?

事实上,两者都有使用,具体看情况。

小于求最短路得到最大值,

大于求最长路得到最小值。

2.2.无解情况

并不是所有差分约束方程都有解。大致可分为两类:

2.2.1.条件矛盾

顾名思义,满足了条件A就无法满足条件B。


等价于:


2.2.2.无关未知数

这个其实不一定算无解,不过和2.2.1判断方法一致,就勉强算无解吧。
未知数没有构成强连通分量。


这里
毫无关联。


2.2.3.判断无解

最短路有负环或最长路有正环即为无解。

2.3.超级原点

超级原点连接到所有点,且权值都是0。

在求最长路时,可以加入一个超级原点以简化代码。

最短路似乎好像也许可能可以加入超级原点,不过容易引起错误。

2.4.去除重边

重复的边会容易导致错误(误判负环)
去重边的伪代码

  1. flag <- 1
  2. for i in G[u]
  3. if G[u,i].v = v
  4. if w better than G[u,i].w
  5. set new G[u,i].w
  6. flag <- 0;
  7. if flag = 1
  8. G[u].append(v, w)

3.模板代码

就是一个spfa模板(最长路):

  1. bool spfa() {
  2. memset(d, 0xef, sizeof(d));
  3. d[0] = 0;
  4. q.push(0);
  5. tx[0] = 1;
  6. while(!q.empty()) {
  7. int u = q.front();
  8. q.pop();
  9. vis[u] = 0;
  10. for(unsigned i = 0; i < G[u].size(); ++i) {
  11. int v = G[u][i].v;
  12. int dis = G[u][i].w;
  13. if (d[v] > d[u] + dis) {
  14. d[v] = d[u] + dis;
  15. if (++tx[v] >= 40) {
  16. return 0;
  17. }
  18. if (!vis[v]) {
  19. q.push(v);
  20. vis[v] = 1;
  21. }
  22. }
  23. }
  24. }
  25. return 1;
  26. }

最短路时改一下符号:

  1. if (dis[v] < dis[u] + w) {
  2. --snip--
  3. }

4.例题

P1993 小K的农场

模板题,长短路均可,主要问题是如何插入边:

  1. scanf("%d %d", &n, &m);
  2. for (int i = 1; i <= m; ++i) {
  3. scanf("%d %d %d", &t, &a, &b);
  4. if (t == 3) {
  5. G[a].push_back(node(b, 0));
  6. G[b].push_back(node(a, 0));
  7. } else {
  8. scanf("%d", &c);
  9. if (t == 1) {
  10. G[a].push_back(node(b, c));
  11. } else {
  12. G[b].push_back(node(a, -c));
  13. }
  14. }
  15. }

tyvj-p1277 关系运算图

好像现在看不到题了:

Description

给出一有向图,图中每条边都被标上了关系运算符‘<’,‘>’,‘=’。现在要给图中每个顶点标上一个大于等于0,小于等于k的某个整数使所有边上的符号得到满足。若存在这样的k,则求最小的k,若任何k都无法满足则输出NO。

例如下表中最小的k为2。

结点1>结点2

结点2>结点3

结点2>结点4

结点3=结点4

如果存在这样的k,输出最小的k值;否则输出‘NO’。

Input

共二行,第一行有二个空格隔开的整数n和m。n表示G的结点个数,m表示G的边数,其中1<=n<=1000, 0<=m<=10000。全部结点用1到n标出,图中任何二点之间最多只有一条边,且不存在自环。

第二行共有3m个用空格隔开的整数,第3i-2和第3i-1(1<=i<=m)个数表示第i条边的顶点。第3i个数表示第i条边上的符号,其值用集合{-1,0,1}中的数表示:-1表示‘<’, 0 表示‘=’, 1表示‘>’。

Output

仅一行,如无解则输出‘NO’;否则输出最小的k的值。

Sample Input

4 4

1 2 -1
2 3 0
2 4 -1
3 4 -1

Sample Output

2

模板题,最长路

HDU3440 House Man

最短路,如果最高楼在最矮楼左边就翻转高度数组。

@2019-7-31 贵州铜仁镇远古镇

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注