Workspace IndexAlgorithms › Day 12

Max Flow, Min Cut, and Matching TODO

Algorithms · Day 12 / 100 · A. Advanced Algorithms & Data Structures (Day 1-19)

Concept

A flow network is a directed graph where every edge has a capacity, and the max-flow problem asks for the largest flow that can be pushed from a source to a sink. The max-flow min-cut theorem says that the minimum total capacity over all cuts separating the source and sink equals the maximum flow exactly — a combinatorial instance of LP duality. The basic algorithmic approach is to repeatedly find an augmenting path in the residual graph and push flow along it; depending on how the path is chosen, this splits into Edmonds-Karp (shortest augmenting path) or Dinic's algorithm (level graph plus blocking flow). Bipartite matching reduces to a flow problem where every capacity is set to 1, and in that setting König's theorem — that the maximum matching size equals the minimum vertex cover size — follows as a special case of the min-cut theorem. Once cost is factored in, this generalizes to min-cost max-flow (MCMF), the general form of resource-to-demand allocation.

Whenever a "who gets what, how much" question comes up — scheduling, order allocation, node-to-shard assignment — it usually reduces to flow or matching, and getting the model wrong means ending up writing an exponential-time search instead.

Code & Formula

# Day 12: 최대 유량·최소 컷과 매칭 — Edmonds-Karp로 최대 유량을 구하고 최소 컷을 복원
# BFS로 최단 증가 경로를 찾아 유량을 밀어 넣고, 잔여 그래프에서 도달 가능한 집합이 곧 최소 컷이다.

from collections import defaultdict, deque

def edmonds_karp(capacity, source, sink):
    graph = defaultdict(dict)
    for (u, v), cap in capacity.items():
        graph[u][v] = graph[u].get(v, 0) + cap
        graph[v].setdefault(u, 0)

    def bfs_path():
        parent = {source: None}
        queue = deque([source])
        while queue:
            u = queue.popleft()
            if u == sink:
                break
            for v, cap in graph[u].items():
                if cap > 0 and v not in parent:
                    parent[v] = u
                    queue.append(v)
        if sink not in parent:
            return None
        path, v = [], sink
        while parent[v] is not None:
            path.append((parent[v], v))
            v = parent[v]
        return list(reversed(path))

    flow = 0
    while True:
        path = bfs_path()
        if path is None:
            break
        path_flow = min(graph[u][v] for u, v in path)
        for u, v in path:
            graph[u][v] -= path_flow
            graph[v][u] += path_flow
        flow += path_flow

    reachable, queue = {source}, deque([source])
    while queue:
        u = queue.popleft()
        for v, cap in graph[u].items():
            if cap > 0 and v not in reachable:
                reachable.add(v); queue.append(v)
    min_cut = [(u, v) for (u, v) in capacity if u in reachable and v not in reachable]
    return flow, min_cut

capacity = {
    ("S", "A"): 3, ("S", "B"): 2,
    ("A", "B"): 1, ("A", "T"): 2,
    ("B", "T"): 3,
}
max_flow, min_cut = edmonds_karp(capacity, "S", "T")
print("최대 유량 =", max_flow)
print("최소 컷 간선 =", min_cut, "(용량 합 =", sum(capacity[e] for e in min_cut), ")")

Exercise

Implement bipartite matching using Dinic's algorithm, then, for the same input, reconstruct the minimum vertex cover from the minimum cut and verify König's theorem in code.

Practical Connection

Splitting multiple orders across multiple liquidity sources for fills, or netting a large set of debt-credit relationships at settlement to reduce the number of on-chain transfers, both fall out naturally as min-cost flow models.

Where it lands in Jayverse

Key expressions

Words and phrases from this page worth keeping, with the Korean meaning and the sentence they come from.

Expression뜻 · 쓰이는 자리
reduces to~로 환원되다, 결국 ~ 문제가 되다 · 복잡한 문제를 더 단순한 형태로 바꿔 풀 때 · "Bipartite matching reduces to a flow problem"
falls out naturally as자연스럽게 ~로 도출되다 · 별도 모델링 없이도 저절로 그 형태가 나온다는 뜻 · "both fall out naturally as min-cost flow models"
follows as a special case~의 특수한 경우로서 성립하다 · 더 일반적인 정리에서 자동으로 따라 나오는 결과 · "follows as a special case of the min-cut theorem"
end up -ing결국 ~하게 되다 · 잘못된 모델링을 하면 비효율적인 방법에 빠지게 된다는 뜻 · "ending up writing an exponential-time search instead"
net (v.)(채권채무를) 상계처리하다 · 여러 거래를 서로 상쇄시켜 이체 건수를 줄이는 것 · "netting a large set of debt-credit relationships"
push flow along(경로를 따라) 흐름을 밀어넣다 · 그래프 알고리즘에서 유량을 보내는 동작 · "push flow along it"
LP선형계획법(Linear Programming) · 최대유량-최소컷 정리가 LP 쌍대성의 조합론적 특수 사례임을 설명할 때. "a combinatorial instance of LP duality"
MCMF최소비용 최대유량(Min-Cost Max-Flow) · 비용까지 고려한 자원-수요 배분 문제의 일반형. "generalizes to min-cost max-flow (MCMF)"
König's theorem쾨니그 정리 · 이분그래프에서 최대 매칭 크기가 최소 정점 커버 크기와 같다는 정리, 최소컷 정리의 특수 사례. "König's theorem — that the maximum matching size equals"

If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/dev-100-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.


한국어

최대 유량·최소 컷과 매칭 TODO

Algorithms · Day 12 / 100 · A. 고급 알고리즘·자료구조 (Day 1–19)

자원 배분 문제의 원형

개념

유량 네트워크는 각 간선에 용량이 있는 방향 그래프이고, 소스에서 싱크로 보낼 수 있는 최대 유량을 구하는 문제가 최대 유량 문제다. 최대 유량-최소 컷 정리는 소스와 싱크를 분리하는 컷 중 용량 합이 최소인 값이 최대 유량과 정확히 같다고 말하며, 이는 선형계획법 쌍대성의 조합론적 사례다. 알고리즘은 잔여 그래프(residual graph)에서 증가 경로를 찾아 유량을 밀어 넣는 방식이 기본이고, 경로 선택 전략에 따라 Edmonds-Karp(최단 증가 경로)나 Dinic(레벨 그래프 + 블로킹 유량)으로 나뉜다. 이분 매칭은 모든 용량을 1로 둔 유량 문제로 환원되며, 이때 최대 매칭 크기가 최소 정점 덮개 크기와 같다는 König 정리가 최소 컷 정리의 특수형으로 따라 나온다. 비용까지 고려하면 최소 비용 최대 유량(MCMF)으로 확장되어, 자원-수요 배분의 일반형이 된다.

스케줄링, 주문 배정, 노드-샤드 할당처럼 "누구에게 무엇을 얼마나" 문제가 나오면 대부분 유량 또는 매칭으로 환원되며, 잘못 모델링하면 지수 시간 탐색을 짜게 된다.

코드 · 수식

# Day 12: 최대 유량·최소 컷과 매칭 — Edmonds-Karp로 최대 유량을 구하고 최소 컷을 복원
# BFS로 최단 증가 경로를 찾아 유량을 밀어 넣고, 잔여 그래프에서 도달 가능한 집합이 곧 최소 컷이다.

from collections import defaultdict, deque

def edmonds_karp(capacity, source, sink):
    graph = defaultdict(dict)
    for (u, v), cap in capacity.items():
        graph[u][v] = graph[u].get(v, 0) + cap
        graph[v].setdefault(u, 0)

    def bfs_path():
        parent = {source: None}
        queue = deque([source])
        while queue:
            u = queue.popleft()
            if u == sink:
                break
            for v, cap in graph[u].items():
                if cap > 0 and v not in parent:
                    parent[v] = u
                    queue.append(v)
        if sink not in parent:
            return None
        path, v = [], sink
        while parent[v] is not None:
            path.append((parent[v], v))
            v = parent[v]
        return list(reversed(path))

    flow = 0
    while True:
        path = bfs_path()
        if path is None:
            break
        path_flow = min(graph[u][v] for u, v in path)
        for u, v in path:
            graph[u][v] -= path_flow
            graph[v][u] += path_flow
        flow += path_flow

    reachable, queue = {source}, deque([source])
    while queue:
        u = queue.popleft()
        for v, cap in graph[u].items():
            if cap > 0 and v not in reachable:
                reachable.add(v); queue.append(v)
    min_cut = [(u, v) for (u, v) in capacity if u in reachable and v not in reachable]
    return flow, min_cut

capacity = {
    ("S", "A"): 3, ("S", "B"): 2,
    ("A", "B"): 1, ("A", "T"): 2,
    ("B", "T"): 3,
}
max_flow, min_cut = edmonds_karp(capacity, "S", "T")
print("최대 유량 =", max_flow)
print("최소 컷 간선 =", min_cut, "(용량 합 =", sum(capacity[e] for e in min_cut), ")")

연습

이분 매칭을 Dinic으로 직접 구현하고, 같은 입력에 대해 최소 정점 덮개를 최소 컷에서 복원해 König 정리를 코드로 확인해 볼 것.

실무 · Verex 연결

여러 주문을 여러 유동성 소스에 나눠 체결하거나, 정산 시 다수 채무-채권 관계를 상계(netting)해 온체인 전송 횟수를 줄이는 문제는 최소 비용 유량으로 자연스럽게 모델링된다.

Jayverse에서의 위치

핵심 표현

이 페이지의 영어 본문에서 배울 만한 단어와 표현, 뜻과 나온 자리.

Expression뜻 · 쓰이는 자리
reduces to~로 환원되다, 결국 ~ 문제가 되다 · 복잡한 문제를 더 단순한 형태로 바꿔 풀 때 · "Bipartite matching reduces to a flow problem"
falls out naturally as자연스럽게 ~로 도출되다 · 별도 모델링 없이도 저절로 그 형태가 나온다는 뜻 · "both fall out naturally as min-cost flow models"
follows as a special case~의 특수한 경우로서 성립하다 · 더 일반적인 정리에서 자동으로 따라 나오는 결과 · "follows as a special case of the min-cut theorem"
end up -ing결국 ~하게 되다 · 잘못된 모델링을 하면 비효율적인 방법에 빠지게 된다는 뜻 · "ending up writing an exponential-time search instead"
net (v.)(채권채무를) 상계처리하다 · 여러 거래를 서로 상쇄시켜 이체 건수를 줄이는 것 · "netting a large set of debt-credit relationships"
push flow along(경로를 따라) 흐름을 밀어넣다 · 그래프 알고리즘에서 유량을 보내는 동작 · "push flow along it"
LP선형계획법(Linear Programming) · 최대유량-최소컷 정리가 LP 쌍대성의 조합론적 특수 사례임을 설명할 때. "a combinatorial instance of LP duality"
MCMF최소비용 최대유량(Min-Cost Max-Flow) · 비용까지 고려한 자원-수요 배분 문제의 일반형. "generalizes to min-cost max-flow (MCMF)"
König's theorem쾨니그 정리 · 이분그래프에서 최대 매칭 크기가 최소 정점 커버 크기와 같다는 정리, 최소컷 정리의 특수 사례. "König's theorem — that the maximum matching size equals"

공부한 날 원본 커리큘럼(docs/knowledge/dev-100-curriculum.md)의 이 줄에 노트 링크와 ✅ 를 붙이면, 이 자리는 노트 본문으로 바로 이어집니다. 노트 없이 이 페이지에 바로 적어도 됩니다 — 다만 다시 생성하면 덮어쓰이므로, 남길 글은 docs/algorithms/ 의 마크다운으로 쓰는 편이 안전합니다.

← 1064. 위상정렬·DAG 스케줄링1066. 선형계획과 쌍대성 직관 →