Dev Study
← アルゴリズムの手法 — CLRS を読むための地図
レッスン 11 / 13·約 9 分·第29期 アルゴリズムの手法 — CLRS を読むための地図

流せる量は一番細い切れ目で決まる — 最大フロー=最小カット

アプリと DB の下に何が積まれているか(左が下、右が上)
  1. 物理機リージョン/AZ
  2. ハイパーバイザVM exit で捕まえる
  3. VMゲストOS
  4. コンテナnamespace / cgroup
  5. プロセスアプリ / DB今ここ

最短路(第8・9回)と最小全域木(第10回)は「何を確定してよいか」の話です。今回は辺に容量があるときに、全体でどれだけ流せるかを扱います。

まず結論

源 s から先 t へ同時に流せる量は、頂点を s 側と t 側に分けたとき「s 側から t 側へ渡る辺の容量の和」(カットの容量)を超えられません。しかも最小のカットの容量にちょうど届きます。同じ関係を、Ford と Fulkerson は 1956 年の論文で(向きのない網と、辺の集まりとしてのカットで)minimal cut theorem として示しました。

届かせる手順の要は、一度流した分を押し戻せる逆向きの辺(残余グラフ)です。これが無いと、辺5本の小さな例でも最大2のところ1で止まります。

? 読む前に予測

容量1の辺が5本: s→a, s→b, a→b, a→t, b→t。最初に s→a→b→t へ1流しました。あとは元の辺の残り容量だけを使い、逆向きには流さずに流し足します。合計はいくつになるでしょうか。

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

どの切れ目も上限になる

辺ごとに容量(同時に流せる上限)があるネットワークで、源 s から先 t へ同時にどれだけ流せるかを考えます。途中の頂点では、入った量と出る量が等しいとします。

ここで頂点を2組に分けます。s を含む側と、t を含む側です。最小全域木の回でも使ったカットという語を、ここでは容量で数えます。カットの容量は、s 側から t 側へ向かう辺の容量の和です。t 側から s 側へ戻る辺は数えません。

s を出た流れは、t に着くまでにどこかで必ず s 側から t 側へ渡ります。だからどのカットを選んでも、その容量は流せる量の上限です。上限がいくつもあるなら、効くのは一番小さいもの、つまり一番細い切れ目です。

辺5本の例(容量はすべて1)と、4通りのカット
s源
s→a 1 / s→b 1
a
b
a→b 1(a から b へ)/ a→t 1 / b→t 1
t先
  • ・s 側 {s}: 2 / {s,a}: 3 / {s,b}: 2 / {s,a,b}: 2
  • ・最小は2。流せる量は2を超えられない

驚くべきなのは逆向きの主張です。最小のカットの容量には、実際に届く。上限がただの上限で終わらず、ちょうど等しくなります。これが最大フロー最小カット定理です。証明はこの教材では扱いません。

具体実物

1956 年の論文は、鉄道網の問いから始まる

Ford と Fulkerson の論文 "Maximal Flow Through a Network"(Canadian Journal of Mathematics 8, 399–404、1956)は、問題の出どころを冒頭に書いています。

The problem discussed in this paper was formulated by T. Harris as follows: "Consider a rail network connecting two cities by way of a number of intermediate cities, where each link of the network has a number assigned to it representing its capacity. Assuming a steady state condition, find a maximal flow from one given city to the other."

この論文の網は向きのない辺(arc)でできていて、カットは辺の集まりとして定義されています。本教材の数え方とは形が違います。

A disconnecting set is a collection of arcs which has the property that every chain joining a and b meets the collection. A disconnecting set, no proper subset of which is disconnecting, is a cut.

そして定理1です。

THEOREM 1. (Minimal cut theorem). The maximal flow value obtainable in a network N is the minimum of v(D) taken over all disconnecting sets D.

ただし同じ冒頭に、こう書かれています。

In §1 we prove the minimal cut theorem, which establishes that an obvious upper bound for flows over an arbitrary network can always be achieved. The proof is non-constructive.

証明は非構成的、つまり「届く」ことは示しても、届かせる手順は与えていません。§2 の計算手続きは、ネットワークを平面的なものに限ったうえでの話です。この論文を「増加路のアルゴリズムの論文」と紹介するのは誤りです。

同じ1956年には、Elias・Feinstein・Shannon の "A note on the maximum flow through a network"(IRE Transactions on Information Theory 2(4), 117–119)も出ています。本教材は本文を確認できていないため、内容には触れません。

上の図の例を手で確かめます。頂点が4つなので、s と t 以外の2頂点をどちらの側に入れるかで、カットは 2^(4−2) = 4 通りです(Python 3.14.6 / macOS arm64、2026-10-07)。

全カットの総当たりと最大フロー(辺5本の例。ex11_maxflow.py と手元の計算を整形)コマンド出力
S={s} 渡る辺 s→a, s→b 容量 2
S={s,a} 渡る辺 s→b, a→b, a→t 容量 3
S={s,b} 渡る辺 s→a, b→t 容量 2
S={s,a,b} 渡る辺 a→t, b→t 容量 2
brute-force min cut over 4 cuts: value=2 maxflow=2 一致

4通りの最小が2で、最大フローも2。S={s,b} で a→b を数えていないのは、t 側の a から s 側の b へ向かう辺だからです。

✓ ここまでの確認

予測の5本の辺で、s 側を {s, b}、t 側を {a, t} としたカットの容量はいくつですか。

抽象原理

一度流した分を押し戻せる辺が、最大へ届かせる

最大に届かせる手順の基本はこうです。s から t へ、まだ流せる道(増加路)を探し、その道の残り容量の最小値だけ流す。道が見つからなくなるまで繰り返す。

ところが、元の辺の残り容量だけで道を探すと失敗します。予測の問いがそれでした。最初に s→a→b→t を選ぶと、s→a・a→b・b→t が埋まり、残る s→b と a→t では s から t へつながりません。

最初に s→a→b→t を流したあと(ex11_maxflow.py の出力。道の表記を整形、Python 3.14.6 / macOS arm64)コマンド出力
then without reverse edges: flow=1 paths=[s→a→b→t (1)] (stuck below max)
then with reverse edges : flow=2 paths=[s→a→b→t (1), s→b→a→t (1)]

直すのが押し戻しの辺です。a→b に1流したら、逆向きの b→a に「取り消せる量1」を持たせます。2本目の道 s→b→a→t は b→a を通り、a→b の1を打ち消します。合わせると s→a→t と s→b→t の2本が残り、最大の2に届きます。

残り容量と押し戻しの辺を合わせたものを残余グラフと呼びます。前提は、一度決めた流し方を後から部分的に取り消せることです。 取り消せない貪欲な流し方は、道を選ぶ順番しだいで最大の手前で止まります。この例でも、幅優先で短い道 s→a→t と s→b→t を先に選べば、押し戻しなしで2に届きました。順番に頼らないために押し戻しの辺を持ちます。

どの道を選ぶかは時間にも効きます。幅優先で辺の数が最少の増加路を選ぶと、多項式時間に収まることが示されています(Edmonds & Karp 1972、Journal of the ACM 19(2))。本教材は原論文の本文を確認できていないため、上限の式は書きません。

実際のライブラリが同じ手順とは限りません。NetworkX 3.7 の maximum_flow は、既定を次のように書いています。

If flow_func is None, the default maximum flow function (preflow_push()) is used. See below for alternative algorithms. The choice of the default function may change from version to version and should not be relied on.

既定は増加路ではなく preflow_push() で、しかも版で変わりうると明記されています。

具体実物

回線の帯域と、人と仕事の割り当て

① 2拠点間の回線帯域。 頂点6・辺9のネットワークで、容量を回線の帯域(単位は任意)と読みます。

辺s→as→ca→ba→ca→db→tc→dd→bd→t
容量1010428109610

s から出る辺の合計は20、t に入る辺の合計も20です。ところが最大フローは19でした。

ex11_maxflow.py の出力(graph2、Python 3.14.6 / macOS arm64)コマンド出力
maxflow=19 via 4 augmenting paths
brute-force min cut over 16 cuts (=2^(V-2)=16): value=19 S=['c', 's'] agree=True

最小のカットは S={s,c} で、渡る辺は s→a(10)と c→d(9)、合わせて19。出口でも入口でもなく、途中の切れ目が細いのです。経路を何本足しても、この切れ目を太くしない限り19は超えません。

② 2部マッチング。 人 p1〜p3 と仕事 j1〜j3 があり、p1 は j1 か j2、p2 は j1 だけ、p3 は j2 か j3 ができます。s から各人へ、できる仕事へ、各仕事から t へ、すべて容量1の辺を張ると、流れ1本が「1人に1つの仕事」になります。

ex11_maxflow.py の出力(2部マッチング 3×3。道の表記を整形)コマンド出力
maxflow=3 augmenting paths=[ s→p1→j1→t (1), s→p3→j2→t (1),
s→p2→j1→p1→j2→p3→j3→t (1) ]
matching=[('p1','j2'), ('p2','j1'), ('p3','j3')] brute-force max matching=3 agree=True

3本目の道が逆向きの j1→p1・j2→p3 を通っています。押し戻しの辺は、割り当ての付け替えになります。 p1 を j1 から j2 へ、p3 を j2 から j3 へずらし、空いた j1 を p2 に渡しています。最初の2組で確定していたら、p2 は仕事を得られず2組で止まります。

✓ ここまでの確認

2部マッチングの実測で、3本目の増加路 s→p2→j1→p1→j2→p3→j3→t は j1→p1 と j2→p3 を通りました。割り当てでいうと何をしていますか。

⇄ 2つを見比べる
具体例 A

2拠点間の回線帯域

s の出口も t の入口も合計20あるのに、最大は19。途中の切れ目 s→a と c→d の合計19が上限になっていました。

具体例 B

人と仕事の割り当て

容量1の流れに直すと、マッチングの数が流れの量になります。最大3に届くには、3本目の道で既存の割り当てを2つ付け替える必要がありました。

帯域の計算と割り当ての計算は見た目が違いますが、どちらでも「押し戻しの辺」が無いと困る場面があります。それぞれ何にあたるでしょうか。

押し戻しの辺を通ることは「前に決めたことを一部取り消す」ことです。帯域なら何を取り消し、割り当てなら何を取り消すかを考えてください。

この章のまとめ

  • どのカットも上限。 カットの容量は s 側から t 側へ向かう辺の容量の和で、逆向きの辺は数えない。
  • 最小のカットに実際に届く。 同じ関係を Ford & Fulkerson 1956 が定理1として示した(向きのない網・辺の集まりとしてのカット)。ただし同論文は証明を「non-constructive」と書き、計算手続きは平面的なネットワークに限る。増加路の一般の手順をこの論文に帰さない。
  • 届かせる要は押し戻しの辺。 辺5本の例で、押し戻しなしは1で止まり、ありで2。6頂点の例は19、マッチングは3で、いずれも総当たりと一致した。
  • 前提は「決めたことを後から部分的に取り消せる」こと。 割り当てでは付け替えにあたる。
  • ライブラリの既定は確かめる。 NetworkX 3.7 の既定は preflow_push() で、版で変わりうると明記されている。

既存クイズでは、「アルゴリズムとデータ構造 III(発展編)」の algorithm-3-18 が対応します。

CLRS(『アルゴリズムイントロダクション』)の目次や索引で maximum flow(最大フロー) を探すと、この回の内容に対応する章や節が見つかります。章の題と番号は版で変わるので、手元の目次で確かめてください。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 3正解: 0

最大フロー最小カット定理が言っていることはどれですか。

用語集(3語)
カット(s-t カット)
頂点を、s を含む側と t を含む側の2組に分けること。その容量は s 側から t 側へ向かう辺の容量の和で、t 側から s 側へ向かう辺は数えない。Ford & Fulkerson 1956 は向きのない網で考え、取り除くと a から b への道が全部切れる辺の集まり(disconnecting set)のうち、真部分集合では切れない極小のものをカットと定義している。
増加路
残余グラフの上で s から t へ、残り容量が正の辺だけでつながる道。その道の残り容量の最小値だけ流し足せる。
残余グラフ
各辺の残り容量に加えて、流した分だけ逆向きの辺(押し戻しの辺)を持たせたグラフ。逆向きに流すことは、前に流した分を取り消すことにあたる。