scipy.sparse.csgraph.maximum_flow¶
- scipy.sparse.csgraph.maximum_flow(csgraph, source, sink)¶
最大化图形中两个顶点之间的流量。
1.4.0 新版功能.
- 参数
- csgraphcsr_matrix
方阵表示有向图,其第(i,j)项是表示顶点i和j之间的边的容量的整数。
- source集成
流从其流出的源顶点。
- sink集成
流流向的水槽顶点。
- method: {{'edmonds_karp', 'dinic'}}, optional
用于计算最大流量的方法/算法。支持以下方式:
默认值为‘dinic’。
1.8.0 新版功能.
- 退货
- resMaximumFlowResult
属性表示的最大流
MaximumFlowResult
中的流的值flow_value
,和中的残差图residual
。
- 加薪
- 类型错误:
如果输入图形不是CSR格式。
- ValueError:
如果容量值不是整数,或者源或接收器超出界限。
注意事项
这解决了给定有向加权图上的最大流问题:流与每条边关联一个值,也称为流,该值小于边的容量,因此对于每个顶点(源顶点和汇点顶点除外),总传入流等于总传出流。流的值是离开源顶点的所有边的流的总和,而最大流问题包括寻找值最大的流。
根据最大流最小割定理,流的最大值也是最小割中各边的权重之和。
为了解决这个问题,我们提供了Edmonds--Karp [1] 和Dinic的算法 [4]. 这两种算法的实现都努力利用稀疏性。前者的时间复杂性 \(O(|V|\,|E|^2)\) 它的空间复杂度是 \(O(|E|)\) 。后者通过构建层级图并在其中发现阻塞流来实现其性能。它的时间复杂度是 \(O(|V|^2\,|E|)\) 它的空间复杂度是 \(O(|E|)\) 。
最大流问题通常定义为实值容量,但我们要求所有容量都是积分,以确保收敛。在处理合理的容量时,或处理属于以下内容的容量时 \(x\mathbb{{Q}}\) 对于一些固定的 \(x \in \mathbb{{R}}\) 因此,通过相应地调整所有容量,可以将问题简化为整体情况。
例如,求解最大流问题可用于计算机视觉中的图割优化 [3].
参考文献
- 1(1,2)
Edmonds,J.和Karp,R.M.网络流问题算法效率的理论改进。1972年。ACM杂志。19(2):第248-264页
- 2
科曼,T.H.和莱瑟森,C.E.和Rivest,R.L.和Stein C.算法导论。第二版。2001年。麻省理工学院出版社。
- 3
- 4(1,2)
用功率估计解决网络中最大流问题的算法。在苏联数学课上。DokLady,Vol.11,第1277-1280页。1970年
示例
也许最简单的流问题是只有两个顶点的图,其边从source(0)到ink(1):
(0) --5--> (1)
这里,最大流量就是边缘的容量:
>>> from scipy.sparse import csr_matrix >>> from scipy.sparse.csgraph import maximum_flow >>> graph = csr_matrix([[0, 5], [0, 0]]) >>> maximum_flow(graph, 0, 1).flow_value 5 >>> maximum_flow(graph, 0, 1, method='edmonds_karp').flow_value 5
另一方面,如果源和宿之间存在瓶颈,则可能会减少最大流量::
(0) --5--> (1) --3--> (2)
>>> graph = csr_matrix([[0, 5, 0], [0, 0, 3], [0, 0, 0]]) >>> maximum_flow(graph, 0, 2).flow_value 3
中给出了一个不那么琐碎的例子。 [2], 第261章:
>>> graph = csr_matrix([[0, 16, 13, 0, 0, 0], ... [0, 0, 10, 12, 0, 0], ... [0, 4, 0, 0, 14, 0], ... [0, 0, 9, 0, 0, 20], ... [0, 0, 0, 7, 0, 4], ... [0, 0, 0, 0, 0, 0]]) >>> maximum_flow(graph, 0, 5).flow_value 23
可以将在二部图中寻找最大匹配的问题简化为最大流问题: \(G = ((U, V), E)\) 是一个二部图。然后,将带有边的源折点添加到图中的每个折点 \(U\) 中每个顶点都有边的接收器顶点。 \(V\) 。最后,将结果图中的每条边的容量指定为1。然后,新图中的最大流在由中的边组成的原始图中提供最大匹配 \(E\) 他的流量是正的。
假设边由一个 \(\lvert U \rvert \times \lvert V \rvert\) CSR格式的矩阵,其 \((i, j)\) ‘如果有边缘来自,则第1个条目为1 \(i \in U\) 至 \(j \in V\) 否则为0;即,输入的格式为
maximum_bipartite_matching
。则上面构造的图的csr表示包含该矩阵作为挡路。下面是一个示例:>>> graph = csr_matrix([[0, 1, 0, 1], [1, 0, 1, 0], [0, 1, 1, 0]]) >>> print(graph.toarray()) [[0 1 0 1] [1 0 1 0] [0 1 1 0]] >>> i, j = graph.shape >>> n = graph.nnz >>> indptr = np.concatenate([[0], ... graph.indptr + i, ... np.arange(n + i + 1, n + i + j + 1), ... [n + i + j]]) >>> indices = np.concatenate([np.arange(1, i + 1), ... graph.indices + i + 1, ... np.repeat(i + j + 1, j)]) >>> data = np.ones(n + i + j, dtype=int) >>> >>> graph_flow = csr_matrix((data, indices, indptr)) >>> print(graph_flow.toarray()) [[0 1 1 1 0 0 0 0 0] [0 0 0 0 0 1 0 1 0] [0 0 0 0 1 0 1 0 0] [0 0 0 0 0 1 1 0 0] [0 0 0 0 0 0 0 0 1] [0 0 0 0 0 0 0 0 1] [0 0 0 0 0 0 0 0 1] [0 0 0 0 0 0 0 0 1] [0 0 0 0 0 0 0 0 0]]
此时,我们可以找到添加的汇和添加的源之间的最大流量,通过将残差图限制到原始图对应的挡路即可得到期望的匹配:
>>> flow = maximum_flow(graph_flow, 0, i+j+1, method='dinic') >>> matching = flow.residual[1:i+1, i+1:i+j+1] >>> print(matching.toarray()) [[0 1 0 0] [1 0 0 0] [0 0 1 0]]
这告诉我们第一个、第二个和第三个顶点 \(U\) 中的第二个、第一个和第三个顶点匹配 \(V\) 分别为。
虽然这通常解决了最大二部匹配问题,但请注意,专门针对该问题的算法,如
maximum_bipartite_matching
,通常会表现得更好。该方法还可用于解决最大二部匹配问题的各种常见推广问题。例如,如果某些顶点可以与多于一个其他顶点匹配,则这可以通过适当修改新图的容量来处理。