Day 007-Q4 — 最大流(Ford-Fulkerson)

2026-04-20 青色 / Phase 5 ★★★★★ 最大流(Ford-Fulkerson)

問題

$N$ 頂点 $M$ 辺の有向グラフがある。各辺には容量が設定されている。頂点 1(ソース)から頂点 $N$(シンク)へ流せる最大流量を求めよ。

制約

$2 \le N \le 500$
$1 \le M \le 1000$
$1 \le c_i \le 10^4$

入出力例

入力例 1

4 5
1 2 10
1 3 10
2 3 2
2 4 8
3 4 10

出力例 1

18

ヒント (段階的開示)

ヒント1: 方向性
ソースからシンクへ流せる経路を繰り返し見つけ、各経路で流せる量を加算。
ヒント2: アプローチ
「増加路」を DFS で見つけ、ボトルネック容量を流す。逆辺(残余グラフ)を管理して取り消しも可能。
ヒント3: 誘導
def add_edge(u, v, cap):
    graph[u].append([v, cap, len(graph[v])])
    graph[v].append([u, 0, len(graph[u])-1])  # 逆辺

模範解答 (Python)

import sys
sys.setrecursionlimit(10000)

def main():
    input_data = sys.stdin.read().split()
    idx = 0
    N, M = int(input_data[idx]), int(input_data[idx+1]); idx += 2

    graph = [[] for _ in range(N)]

    def add_edge(u, v, cap):
        graph[u].append([v, cap, len(graph[v])])
        graph[v].append([u, 0, len(graph[u])-1])

    for _ in range(M):
        u, v, c = int(input_data[idx])-1, int(input_data[idx+1])-1, int(input_data[idx+2])
        idx += 3
        add_edge(u, v, c)

    def dfs(v, t, f, visited):
        if v == t:
            return f
        visited[v] = True
        for e in graph[v]:
            if not visited[e[0]] and e[1] > 0:
                d = dfs(e[0], t, min(f, e[1]), visited)
                if d > 0:
                    e[1] -= d
                    graph[e[0]][e[2]][1] += d
                    return d
        return 0

    flow = 0
    INF = float('inf')
    while True:
        visited = [False] * N
        f = dfs(0, N-1, INF, visited)
        if f == 0:
            break
        flow += f

    print(flow)

main()

Step-by-Step 解説

1残余グラフ
辺 $(u\to v, cap=c)$ を使って $f$ 流すと、残余辺 $(u\to v, cap=c-f)$ と逆辺 $(v\to u, cap=f)$ が生まれる。
2増加路の探索
残余グラフ上で $s$ から $t$ へのパスを DFS で探す。
3収束の保証
各反復で少なくとも 1 流れるため、最大流量 $F$ 回で終了。計算量 $O(FE)$。
4逆辺インデックス管理
add_edge 時に rev_index を保存し、後で graph[e[0]][e[2]][1] += d で逆辺を更新。

よくあるミス

ミス原因正しい書き方
逆辺を追加しない残余グラフの概念を知らないadd_edge(v, u, 0)
逆辺の更新を間違えるインデックス管理ミスadd_edge 時に rev_index を保存
再帰上限エラー大きいグラフで DFS が深いsys.setrecursionlimit(10**6) または BFS

次のステップ

  • 発展問題: Dinic 法で $O(V^2 E)$ の最大流

自己評価

自分の回答

気づき・メモ