70 lines
1.8 KiB
Ruby
70 lines
1.8 KiB
Ruby
# cf. http://en.wikipedia.org/wiki/Maximum_flow_problem
|
|
class MaximumFlow
|
|
|
|
# cf. http://en.wikipedia.org/wiki/Push%E2%80%93relabel_maximum_flow_algorithm
|
|
def relabel_to_front(capacities, source, sink)
|
|
n = capacities.length
|
|
flow = Array.new(n) { Array.new(n, 0) }
|
|
height = Array.new(n, 0)
|
|
excess = Array.new(n, 0)
|
|
seen = Array.new(n, 0)
|
|
queue = (0...n).select { |i| i != source && i != sink }.to_a
|
|
|
|
height[source] = n - 1
|
|
excess[source] = Float::INFINITY
|
|
(0...n).each { |v| push(source, v, capacities, flow, excess) }
|
|
|
|
p = 0
|
|
while p < queue.length
|
|
u = queue[p]
|
|
h = height[u]
|
|
discharge(u, capacities, flow, excess, seen, height, n)
|
|
if height[u] > h
|
|
queue.unshift(queue.delete_at(p))
|
|
p = 0
|
|
else
|
|
p += 1
|
|
end
|
|
end
|
|
|
|
flow[source].reduce(:+)
|
|
end
|
|
|
|
private
|
|
|
|
def push(u, v, capacities, flow, excess)
|
|
residual_capacity = capacities[u][v] - flow[u][v]
|
|
send = [excess[u], residual_capacity].min
|
|
flow[u][v] += send
|
|
flow[v][u] -= send
|
|
excess[u] -= send
|
|
excess[v] += send
|
|
end
|
|
|
|
def discharge(u, capacities, flow, excess, seen, height, n)
|
|
while excess[u] > 0
|
|
if seen[u] < n
|
|
v = seen[u]
|
|
if capacities[u][v] - flow[u][v] > 0 && height[u] > height[v]
|
|
push(u, v, capacities, flow, excess)
|
|
else
|
|
seen[u] += 1
|
|
end
|
|
else
|
|
relabel(u, capacities, flow, height, n)
|
|
seen[u] = 0
|
|
end
|
|
end
|
|
end
|
|
|
|
def relabel(u, capacities, flow, height, n)
|
|
min_height = Float::INFINITY
|
|
(0...n).each do |v|
|
|
if capacities[u][v] - flow[u][v] > 0
|
|
min_height = [min_height, height[v]].min
|
|
height[u] = min_height + 1
|
|
end
|
|
end
|
|
end
|
|
end
|