最大流 - Ford-Fulkerson算法:无向图

18

我正在尝试使用Ford-Fulkerson算法解决图的最大流问题。该算法仅针对有向图进行描述。如果图是无向的呢?

为了模拟一个无向图,我所做的是在一对顶点之间使用两个有向边。令我困惑的是:这些边中的每一条都应该有一个剩余边吗?还是说“相反”的有向边就是剩余边?

我假设后者,但我的算法似乎进入了一个无限循环。我希望你们中的任何一个能给我一些帮助。下面是我的实现。我在查找中使用DFS。

import sys
import fileinput

class Vertex(object):
    def __init__(self, name):
        self.name = name
        self.edges = []

    def find(self, sink, path):
        if(self == sink):
            return path
        for edge in self.edges:
            residual = edge.capacity - edge.flow
            if(residual > 0 or edge.inf):
                if(edge not in path and edge.oppositeEdge not in path):
                    toVertex = edge.toVertex
                    path.append(edge)
                    result = toVertex.find(sink, path)
                    if result != None:
                        return result

class Edge(object):
    def __init__(self, fromVertex, toVertex, capacity):
        self.fromVertex = fromVertex
        self.toVertex = toVertex
        self.capacity = capacity
        self.flow = 0
        self.inf = False
        if(capacity == -1):
            self.inf = True
    def __repr__(self):
        return self.fromVertex.name.strip() + " - " + self.toVertex.name.strip()

def buildGraph(vertices, edges):
    for edge in edges:
        sourceVertex = vertices[int(edge[0])]
        sinkVertex = vertices[int(edge[1])]
        capacity = int(edge[2])
        edge1 = Edge(sourceVertex, sinkVertex, capacity)
        edge2 = Edge(sinkVertex, sourceVertex, capacity)
        sourceVertex.edges.append(edge1)
        sinkVertex.edges.append(edge2)
        edge1.oppositeEdge = edge2
        edge2.oppositeEdge = edge1

def maxFlow(source, sink):
    path = source.find(sink, [])
    while path != None:
        minCap = sys.maxint
        for e in path:
            if(e.capacity < minCap and not e.inf):
                minCap = e.capacity

        for edge in path:
            edge.flow += minCap
            edge.oppositeEdge.flow -= minCap
        path = source.find(sink, [])

    return sum(e.flow for e in source.edges)

vertices, edges = parse()
buildGraph(vertices, edges)
source = vertices[0]
sink = vertices[len(vertices)-1]
maxFlow = maxFlow(source, sink)
1个回答

11
您的方法使用两个反向边是可行的。如果您的边是a->b(容量为10,我们将7发送到它),我们引入一个新的残余边(从ba,其残余容量为17,从ab的残余边具有剩余容量3)。
原始的反向边(从ba)可以保持不变,或者新的残余边和原始反向边可以融合成一条边。
我可以想象将残余容量添加到原始反向边中可能会更简单,但我不确定。

感谢您的回答,很抱歉我回复晚了。您对此有多大的把握呢?a->b和b->a的容量都是10。如果我们将7个单位从a->b发送,那么剩余边缘容量(在这种情况下为b->a)不应该是您所说的3,而应该是17吧? - Mads Andersen
我认为你是正确的。我已经相应地更新了我的答案。我最初指的是a->b的剩余容量。 - phimuemue
是的,现在它可以工作了。如果有人看到代码,错误就在查找方法中。我建议使用Dijkstra算法代替。 - Mads Andersen
这正是我一直在寻找的。我研究了Boykov和Kolmogorov的最大流算法,他们在原始实现中也使用了两条边(正向和反向),所以我现在明白了缺失的部分。 - Libor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接