最短路--差分约束系统

本文介绍了一种解决差分约束系统的方法,通过将其转化为图论中的单源最短路径问题来寻找解。文章详细解释了如何构建图以及如何通过最短路径算法找到变量的最大值或最小值。

看了一晚上头都大了。。。以前学的时候不是太懂加上好久没做就更不懂了

http://imlazy.ycool.com/post.1702305.html

http://hi.baidu.com/accplaystation/item/72c9e50dd1eb63e3f45ba6ff

看了这两篇篇文章后有些微懂


总结下来就是这么个结论:

如果做后是取最值

求最大值,把不等式全变为<=,做最短路;
求最值,把不等式全变为>=,做最长路。

如果只是判断是否有解,则同上建好图用spfa判负环即可

(建边都是先建立标准的不等式a-b>=c    (注意一定是>=而不是>)  或者   a-b<=c不等式,左边从减号右边连向左边的有向边,边权为右边的常数

证明看下文。

(本文假设读者已经有以下知识:最短路径的基本性质、Bellman-Ford算法。)
    比如有这样一组不等式:
   

X1 - X2 <= 0
X1 - X5 <= -1
X2 - X5 <= 1
X3 - X1 <= 5
X4 - X1 <= 4
X4 - X3 <= -1
X5 - X3 <= -3
X5 - X4 <= -3

不等式组(1)

    全都是 两个 未知数的差 小于等于 某个常数(大于等于也可以,因为左右乘以-1就可以化成小于等于)。这样的不等式组就称作差分约束系统。
    这个不等式组要么无解,要么就有无数组解。因为如果有一组解{X1, X2, ..., Xn}的话,那么对于任何一个常数k,{X1 + k, X2 + k, ..., Xn + k}肯定也是一组解,因为任何两个数同时加一个数之后,它们的差是不变的,那么这个差分约束系统中的所有不等式都不会被破坏。
    
    差分约束系统的解法利用到了单源最短路径问题中的三角形不等式。即对于任何一条边u -> v,都有:

d(v) <= d(u) + w(u, v)

    其中d(u)和d(v)是从源点分别到点u和点v的最短路径的权值,w(u, v)是边u -> v的权值。
    显然以上不等式就是d(v) - d(u) <= w(u, v)。这个形式正好和差分约束系统中的不等式形式相同。于是我们就可以把一个差分约束系统转化成一张图,每个未知数Xi对应图中的一个顶点Vi,把所有不等式都化成图中的一条边。对于不等式Xi - Xj <= c,把它化成三角形不等式:Xi <= Xj + c,就可以化成边Vj -> Vi,权值为c。最后,我们在这张图上求一次单源最短路径,这些三角形不等式就会全部都满足了,因为它是最短路径问题的基本性质嘛。
    话说回来,所谓单源最短路径,当然要有一个源点,然后再求这个源点到其他所有点的最短路径。那么源点在哪呢?我们不妨自已造一个。以上面的不等式组为例,我们就再新加一个未知数X0。然后对原来的每个未知数都对X0随便加一个不等式(这个不等式当然也要和其它不等式形式相同,即两个未知数的差小于等于某个常数)。我们索性就全都写成Xn - X0 <= 0,于是这个差分约束系统中就多出了下列不等式:
    
X1 - X0 <= 0
X2 - X0 <= 0
X3 - X0 <= 0
X4 - X0 <= 0
X5 - X0 <= 0
不等式组(2)

    对于这5个不等式,也在图中建出相应的边。最后形成的图如下:


图1

    图中的每一条边都代表差分约束系统中的一个不等式。现在以V0为源点,求单源最短路径。最终得到的V0到Vn的最短路径长度就是Xn的一个解啦。从图1中可以看到,这组解是{-5, -3, 0, -1, -4}。当然把每个数都加上10也是一组解:{5, 7, 10, 9, 6}。但是这组解只满足不等式组(1),也就是原先的差分约束系统;而不满足不等式组(2),也就是我们后来加上去的那些不等式。当然这是无关紧要的,因为X0本来就是个局外人,是我们后来加上去的,满不满足与X0有关的不等式我们并不在乎。
    也有可能出现无解的情况,也就是从源点到某一个顶点不存在最短路径。也说是图中存在负权的圈。这一点我就不展开了,请自已参看最短路径问题的一些基本定理。

    其实,对于图1来说,它代表的一组解其实是{0, -5, -3, 0, -1, -4},也就是说X0的值也在这组解当中。但是X0的值是无可争议的,既然是以它作为源点求的最短路径,那么源点到它的最短路径长度当然是0了。因此,实际上我们解的这个差分约束系统无形中又存在一个条件:

X0 = 0

    也就是说在不等式组(1)、(2)组成的差分约束系统的前提下,再把其中的一个未知数的值定死。这样的情况在实际问题中是很常见的。比如一个问题表面上给出了一些不等式,但还隐藏着一些不等式,比如所有未知数都大于等于0或者都不能超过某个上限之类的。比如上面的不等式组(2)就规定了所有未知数都小于等于0。
    
   对于这种有一个未知数定死(实际做时只需保证起点的dis[s]=0即可)的差分约束系统,还有一个有趣的性质,那就是通过最短路径算法求出来的一组解当中,所有未知数都达到最大值。下面我来粗略地证明一下,这个证明过程要结合Bellman-Ford算法的过程来说明。
    假设X0是定死的;X1到Xn在满足所有约束的情况下可以取到的最大值分别为M1、M2、……、Mn(当然我们不知道它们的值是多少);解出的源点到每个点的最短路径长度为D1、D2、……、Dn。
    基本的Bellman-Ford算法是一开始初始化D1到Dn都是无穷大。然后检查所有的边对应的三角形不等式,一但发现有不满足三角形不等式的情况,则更新对应的D值。最后求出来的D1到Dn就是源点到每个点的最短路径长度。
    如果我们一开始初始化D1、D2、……、Dn的值分别为M1、M2、……、Mn,则由于它们全都满足三角形不等式(我们刚才已经假设M1到Mn是一组合法的解),则Bellman-Ford算法不会再更新任合D值,则最后得出的解就是M1、M2、……、Mn。
    好了,现在知道了,初始值无穷大时,算出来的是D1、D2、……、Dn;初始值比较小的时候算出来的则是M1、M2、……、Mn。大家用的是同样的算法,同样的计算过程,总不可能初始值大的算出来的结果反而小吧。所以D1、D2、……、Dn就是M1、M2、……、Mn。
    
    那么如果在一个未知数定死的情况下,要求其它所有未知数的最小值怎么办?只要反过来求最长路径就可以了。最长路径中的三角不等式与最短路径中相反:

d(v) >= d(u) + w(u, v) 
也就是 d(v) - d(u) >= w(u, v)

    所以建图的时候要先把所有不等式化成大于等于号的。其它各种过程,包括证明为什么解出的是最小值的证法,都完全类似。


### 差分约束系统求解最短路径问题 差分约束系统是一种特殊的线性规划问题,可以通过将其转换为图论中的单源最短路径问题来高效求解。以下是具体的实现方式: #### 转化为图模型 差分约束系统的每个变量 \( x_i \) 对应于图中的一个节点。对于每一个约束条件 \( x_j - x_i \leq b_k \),可以在图中添加一条从节点 \( i \) 到节点 \( j \) 的有向边,其权重为 \( b_k \)[^2]。 为了确保所有节点都能被访问到,通常引入一个新的超级源点 \( s \),并从 \( s \) 向所有其他节点连一条权重为 0 的边[^3]。 #### 使用 Bellman-Ford 或 SPFA 算法 一旦构建好上述图结构,就可以通过运行 Bellman-Ford 算法或更高效的 SPFA 算法来计算从超级源点 \( s \) 出发到达各节点的最短路径距离。这些距离值实际上对应着满足差分约束的一组可行解。 如果在执行过程中检测到了负权回路,则说明该差分约束系统无解;否则,得到的距离数组即为所需的结果[^5]。 下面是一个基于 Python 的简单实现示例: ```python from collections import deque, defaultdict def spfa(graph, n): dist = [float('inf')] * (n + 1) in_queue = [False] * (n + 1) queue = deque() # 初始化起点 queue.append(0) dist[0] = 0 in_queue[0] = True while queue: u = queue.popleft() in_queue[u] = False for v, w in graph[u]: if dist[v] > dist[u] + w: dist[v] = dist[u] + w if not in_queue[v]: queue.append(v) in_queue[v] = True return dist # 构建图的例子 n = 5 # 假设有5个变量加上虚拟起点共6个节点 graph = defaultdict(list) # 添加一些约束条件作为边 constraints = [ (1, 2, 3), # 表示x2 - x1 <= 3 (2, 3, 1), # 表示x3 - x2 <= 1 (3, 4, 2), # 表示x4 - x3 <= 2 ] for a, b, c in constraints: graph[a].append((b, c)) # 加入虚拟起点指向各个实际点的零权边 for node in range(1, n+1): graph[0].append((node, 0)) distances = spfa(graph, n) print(distances[1:]) # 输出除虚拟起点外的实际变量解 ``` 以上代码展示了如何利用 SPFA 来解决由若干差分不等式构成的约束系统,并获得相应的最短路径解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值