as3: correctly compute flow using push-relabel
This commit is contained in:
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import "core:fmt"
|
||||
import "core:math"
|
||||
import "core:slice"
|
||||
|
||||
// the graph starts with a source s and ends with a sink t, hence the 1s.
|
||||
// then there is a stack of n nodes, then a chain of k nodes, then another stack of m nodes.
|
||||
@@ -61,7 +60,7 @@ print_graph :: proc(g: [$row][$col]$T, elem_sep := " ", line_sep := "\n") {
|
||||
fmt.print(rune('a' + i)) // row markers
|
||||
fmt.print(elem_sep)
|
||||
for j in 0 ..< col {
|
||||
fmt.print(g[i][j])
|
||||
fmt.print(g[i][j] < 0 ? 10 + g[i][j] : g[i][j])
|
||||
fmt.print(elem_sep)
|
||||
}
|
||||
fmt.print(line_sep)
|
||||
@@ -74,7 +73,7 @@ find_node_with_excess :: proc(excesses: []int) -> (u: int, ok: bool) {
|
||||
}
|
||||
|
||||
find_admissible_edge :: proc(u: int, residuals, heights: []int) -> (v: int, ok: bool) {
|
||||
if len(residuals) != len(heights) do return -1, false
|
||||
assert(len(residuals) == len(heights))
|
||||
for r, idx in residuals {
|
||||
if r > 0 && heights[u] == heights[idx] + 1 {
|
||||
return idx, true
|
||||
@@ -83,14 +82,16 @@ find_admissible_edge :: proc(u: int, residuals, heights: []int) -> (v: int, ok:
|
||||
return -1, false
|
||||
}
|
||||
|
||||
push :: proc(u, v: int, residuals, excesses: []int) -> (res: []int, ok: bool) {
|
||||
if len(residuals) != excesses
|
||||
push :: proc(u, v: int, residuals, excesses: []int) -> int {
|
||||
assert(len(residuals) == len(excesses))
|
||||
return min(excesses[u], residuals[v])
|
||||
}
|
||||
|
||||
push_relabel :: proc(graph: [$n][n]int) -> (flow: [n][n]int) {
|
||||
heights: [n]int
|
||||
heights[0] = n
|
||||
flow[0] += graph[0]
|
||||
for _, idx in flow do flow[idx][0] -= graph[idx][0]
|
||||
excesses: [n]int
|
||||
excesses[0] = -math.sum(flow[0][:])
|
||||
excesses += flow[0]
|
||||
@@ -99,9 +100,20 @@ push_relabel :: proc(graph: [$n][n]int) -> (flow: [n][n]int) {
|
||||
u += 1
|
||||
residuals := graph[u] - flow[u]
|
||||
if v, ok := find_admissible_edge(u, residuals[:], heights[:]); ok {
|
||||
flow[u] = push(u, v, residuals[:], excesses[:])
|
||||
assert(heights[u] == heights[v] + 1)
|
||||
delta := push(u, v, residuals[:], excesses[:])
|
||||
flow[u][v] += delta
|
||||
flow[v][u] -= delta
|
||||
excesses[u] -= delta
|
||||
excesses[v] += delta
|
||||
} else {
|
||||
// relabel(u, v, graph, flow)
|
||||
assert(excesses[u] > 0)
|
||||
for r, v in residuals do if r > 0 do assert(heights[u] <= heights[v])
|
||||
m := n
|
||||
for h, v in heights {
|
||||
if residuals[v] > 0 do m = h < m ? h : m
|
||||
}
|
||||
heights[u] = 1 + m
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -110,7 +122,8 @@ push_relabel :: proc(graph: [$n][n]int) -> (flow: [n][n]int) {
|
||||
|
||||
main :: proc() {
|
||||
graph := create_graph(3, 3, 3, 3)
|
||||
print_graph(graph, elem_sep = " ")
|
||||
print_graph(graph, elem_sep = " ")
|
||||
fmt.println()
|
||||
print_graph(push_relabel(graph))
|
||||
print_graph(push_relabel(graph), elem_sep = " ")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user