網絡流的背景我就不多說了,就是在一個有向圖中找出最大的流量,有意思的是,該問題的對偶問題爲最小割,找到一種切分,使得圖的兩邊的流通量最小,而且通常對偶問題是原問題的一個下界,但最小割正好等於最大流,即切割的邊就是最大流中各個path飽和邊的一個組合。說得可能比較含糊,這裏想要了解清楚還是查閱相關資料吧。
最大流最原始最經典的解法就是FF算法,算法複雜度爲O(mC),C爲邊的容量的總和,m爲邊數。而今天講的Push-relabel算法是90年代提出的高效算法,複雜度爲O(n^3),其實網絡流最關鍵的步驟就是添加反向邊,得出剩餘圖。而其他的改進就是爲了在尋找增廣路徑時儘可能貪心,流量儘可能大。
好了,開始講Push-relabel的主要思想,首先構造一個函數excess,代表每個節點保存的流量,就是等於該節點的入流量-出流量,正常來說,s的保存流量爲負,t的保存流量爲正,其他節點的保存流量均爲0,而算法的最終目標就是這個,此外還定義一個height函數(h),表示每個節點的高度。然後,初始化過程是,h(s)=n,h(v)=0,對於所有不爲s的節點,f(s, u)=c(s, u),對於所有從s出發的邊都默認飽和,這是上界。接着,就是Push-relabel的過程了,首先遍歷圖中所有節點,如果存在非t的且excess大於0的節點v,則查看v出發的所有邊(v, w),如果h(v)>h(w),則可以將label,即excess的流量,傳遞給w,如果該邊爲正向邊,傳的大小爲bottleneck=min{excess(v), c(v,w) - f(v, w)},否則bottleneck=min{excess(v), f(v, w)},傳完之後,繼續尋找excess大於0的節點,注意,如果v有邊,但所有邊都是h(v)<h(w),則將v的高度提升1,繼續尋找。
源代碼如下:
注意圖的輸入格式需滿足DIMACS格式。
__author__ = 'xanxus'
nodeNum, edgeNum = 0, 0
arcs = []
class Arc(object):
def __init__(self):
self.src = -1
self.dst = -1
self.cap = -1
s, t = -1, -1
with open('sample.dimacs') as f:
for line in f.readlines():
line = line.strip()
if line.startswith('p'):
tokens = line.split(' ')
nodeNum = int(tokens[2])
edgeNum = tokens[3]
if line.startswith('n'):
tokens = line.split(' ')
if tokens[2] == 's':
s = int(tokens[1])
if tokens[2] == 't':
t = int(tokens[1])
if line.startswith('a'):
tokens = line.split(' ')
arc = Arc()
arc.src = int(tokens[1])
arc.dst = int(tokens[2])
arc.cap = int(tokens[3])
arcs.append(arc)
nodes = [-1] * nodeNum
for i in range(s, t + 1):
nodes[i - s] = i
adjacent_matrix = [[0 for i in range(nodeNum)] for j in range(nodeNum)]
forward_matrix = [[0 for i in range(nodeNum)] for j in range(nodeNum)]
for arc in arcs:
adjacent_matrix[arc.src - s][arc.dst - s] = arc.cap
forward_matrix[arc.src - s][arc.dst - s] = arc.cap
flow_matrix = [[0 for i in range(nodeNum)] for j in range(nodeNum)]
height = [0] * nodeNum
height[0] = nodeNum
for i in range(len(adjacent_matrix)):
flow_matrix[0][i] = adjacent_matrix[0][i]
adjacent_matrix[0][i] = 0
adjacent_matrix[i][0] = flow_matrix[0][i]
def excess(v):
in_flow, out_flow = 0, 0
for i in range(len(flow_matrix)):
in_flow += flow_matrix[i][v]
out_flow += flow_matrix[v][i]
return in_flow - out_flow
def exist_excess():
for v in range(len(flow_matrix)):
if excess(v) > 0 and v != t - s:
return v
return None
v = exist_excess()
while v:
has_lower_height = False
for j in range(len(adjacent_matrix)):
if adjacent_matrix[v][j] != 0 and height[v] > height[j]:
has_lower_height = True
if forward_matrix[v][j] != 0:
bottleneck = min([excess(v), adjacent_matrix[v][j]])
flow_matrix[v][j] += bottleneck
adjacent_matrix[v][j] -= bottleneck
adjacent_matrix[j][v] += bottleneck
else:
bottleneck = min([excess(v), flow_matrix[j][v]])
flow_matrix[j][v] -= bottleneck
adjacent_matrix[v][j] -= bottleneck
adjacent_matrix[j][v] += bottleneck
if not has_lower_height:
height[v] += 1
v = exist_excess()
for arc in arcs:
print 'f %d %d %d' % (arc.src, arc.dst, flow_matrix[arc.src - s][arc.dst - s])
希望對大家有所幫助。