コンテンツにスキップ
Wikipedia

エドモンズ・カープのアルゴリズム

出典: フリー百科事典『ウィキペディア(Wikipedia)』

エドモンズ・カープのアルゴリズム(: Edmonds-Karp algorithm)は、フローネットワーク最大フロー問題を解くフォード・ファルカーソンのアルゴリズムの実装の一種であり、 O ( V E 2 ) {\displaystyle O(VE^{2})} {\displaystyle O(VE^{2})} の計算量である。 O ( V 3 ) {\displaystyle O(V^{3})} {\displaystyle O(V^{3})}relabel-to-front アルゴリズムに比べると漸近的に遅いが、(辺の少ない)疎なグラフでは速い。このアルゴリズムは1970年にロシア人科学者 Dinic が発表し[1] 、それとは独立に1972年にジャック・エドモンズリチャード・カープが発表した[2] (発見はこちらの方が早かった)。Dinic のアルゴリズムには追加の技法が含まれており、計算量は O ( V 2 E ) {\displaystyle O(V^{2}E)} {\displaystyle O(V^{2}E)} となっている。

アルゴリズム

[編集 ]

このアルゴリズムはフォード・ファルカーソンのアルゴリズムとほぼ同じだが、増加道を探索するときの順序が定義されている点だけが異なる。それは、各辺が単位長としたときの幅優先探索である。 O ( V E 2 ) {\displaystyle O(VE^{2})} {\displaystyle O(VE^{2})} の実行時間は、各増加道の探索に O ( E ) {\displaystyle O(E)} {\displaystyle O(E)} の時間がかかり、 E {\displaystyle E} {\displaystyle E} 個の辺のうち毎回少なくとも1つが飽和し、飽和した辺と始点を結ぶ増加道が前回より短くなることはなく、増加道の長さの上限は V {\displaystyle V} {\displaystyle V} である。もう1つのこのアルゴリズムの特性として、最短増加道の長さは単調に増大する。アルゴリズムの妥当性の証明は書籍『アルゴリズムイントロダクション』(ISBN 476490408X) にある[3]

擬似コード

[編集 ]
algorithm EdmondsKarp
 input:
 C[1..n, 1..n] (容量配列)
 E[1..n, 1..?] (隣接リスト)
 s (始点)
 t (終点)
 output:
 f (最大フロー値)
 F (最大値の正当なフローを与えるマトリクス)
 f := 0 (初期フローはゼロ)
 F := array(1..n, 1..n) (u から v への残余容量は C[u,v] - F[u,v])
 forever
 m, P := BreadthFirstSearch(C, E, s, t)
 if m = 0
 break
 f := f + m
 (バックトラックし、フローを書く)
 v := t
 while v ≠ s
 u := P[v]
 F[u,v] := F[u,v] + m
 F[v,u] := F[v,u] - m
 v := u
 return (f, F)
algorithm BreadthFirstSearch
 input:
 C, E, s, t
 output:
 M[t] (見つかった道の容量)
 P (親テーブル)
 P := array(1..n)
 for u in 1..n
 P[u] := -1
 P[s] := -2 (始点を再発見したのではないことを確認するため) 
 M := array(1..n) (見つけた道の容量)
 M[s] := ∞
 Q := queue()
 Q.push(s)
 while Q.size() > 0
 u := Q.pop()
 for v in E[u]
 (まだ容量があり、v がまだ探索されていなかった場合)
 if C[u,v] - F[u,v] > 0 and P[v] = -1
 P[v] := u
 M[v] := min(M[u], C[u,v] - F[u,v])
 if v ≠ t
 Q.push(v)
 else
 return M[t], P
 return 0, P

[編集 ]

7ノードからなるネットワーク(A が始点、G が終点)について、以下のように容量が定義されている。

各辺にある f / c {\displaystyle f/c} {\displaystyle f/c} で、 f {\displaystyle f} {\displaystyle f} は現在のフロー、 c {\displaystyle c} {\displaystyle c} は容量を表す。 u {\displaystyle u} {\displaystyle u} から v {\displaystyle v} {\displaystyle v} の残余容量は c f ( u , v ) = c ( u , v ) f ( u , v ) {\displaystyle c_{f}(u,v)=c(u,v)-f(u,v)} {\displaystyle c_{f}(u,v)=c(u,v)-f(u,v)} で表される(容量から既に使われている分のフローを差し引いた値)。 u {\displaystyle u} {\displaystyle u} から v {\displaystyle v} {\displaystyle v} へのフローが負の場合、残余容量は却って増える。

容量 経路(道)
ネットワーク
min ( c f ( A , D ) , c f ( D , E ) , c f ( E , G ) ) = {\displaystyle \min(c_{f}(A,D),c_{f}(D,E),c_{f}(E,G))=} {\displaystyle \min(c_{f}(A,D),c_{f}(D,E),c_{f}(E,G))=}

min ( 3 0 , 2 0 , 1 0 ) = {\displaystyle \min(3-0,2-0,1-0)=} {\displaystyle \min(3-0,2-0,1-0)=}
min ( 3 , 2 , 1 ) = 1 {\displaystyle \min(3,2,1)=1} {\displaystyle \min(3,2,1)=1}

A , D , E , G {\displaystyle A,D,E,G} {\displaystyle A,D,E,G}
min ( c f ( A , D ) , c f ( D , F ) , c f ( F , G ) ) = {\displaystyle \min(c_{f}(A,D),c_{f}(D,F),c_{f}(F,G))=} {\displaystyle \min(c_{f}(A,D),c_{f}(D,F),c_{f}(F,G))=}

min ( 3 1 , 6 0 , 9 0 ) = {\displaystyle \min(3-1,6-0,9-0)=} {\displaystyle \min(3-1,6-0,9-0)=}
min ( 2 , 6 , 9 ) = 2 {\displaystyle \min(2,6,9)=2} {\displaystyle \min(2,6,9)=2}

A , D , F , G {\displaystyle A,D,F,G} {\displaystyle A,D,F,G}
min ( c f ( A , B ) , c f ( B , C ) , c f ( C , D ) , c f ( D , F ) , c f ( F , G ) ) = {\displaystyle \min(c_{f}(A,B),c_{f}(B,C),c_{f}(C,D),c_{f}(D,F),c_{f}(F,G))=} {\displaystyle \min(c_{f}(A,B),c_{f}(B,C),c_{f}(C,D),c_{f}(D,F),c_{f}(F,G))=}

min ( 3 0 , 4 0 , 1 0 , 6 2 , 9 2 ) = {\displaystyle \min(3-0,4-0,1-0,6-2,9-2)=} {\displaystyle \min(3-0,4-0,1-0,6-2,9-2)=}
min ( 3 , 4 , 1 , 4 , 7 ) = 1 {\displaystyle \min(3,4,1,4,7)=1} {\displaystyle \min(3,4,1,4,7)=1}

A , B , C , D , F , G {\displaystyle A,B,C,D,F,G} {\displaystyle A,B,C,D,F,G}
min ( c f ( A , B ) , c f ( B , C ) , c f ( C , E ) , c f ( E , D ) , c f ( D , F ) , c f ( F , G ) ) = {\displaystyle \min(c_{f}(A,B),c_{f}(B,C),c_{f}(C,E),c_{f}(E,D),c_{f}(D,F),c_{f}(F,G))=} {\displaystyle \min(c_{f}(A,B),c_{f}(B,C),c_{f}(C,E),c_{f}(E,D),c_{f}(D,F),c_{f}(F,G))=}

min ( 3 1 , 4 1 , 2 0 , 0 1 , 6 3 , 9 3 ) = {\displaystyle \min(3-1,4-1,2-0,0--1,6-3,9-3)=} {\displaystyle \min(3-1,4-1,2-0,0--1,6-3,9-3)=}
min ( 2 , 3 , 2 , 1 , 3 , 6 ) = 1 {\displaystyle \min(2,3,2,1,3,6)=1} {\displaystyle \min(2,3,2,1,3,6)=1}

A , B , C , E , D , F , G {\displaystyle A,B,C,E,D,F,G} {\displaystyle A,B,C,E,D,F,G}

このアルゴリズムで発見する増加道(赤で示されている)の長さが決して減少しない点に注意されたい。発見した道は、その時点の最短である。見つかったフローは、グラフの始点と終点を分離するように横切る最小カットをまたぐ容量と等価である。このグラフには最小カットは1つしかなく、 { A , B , C , E } {\displaystyle \{A,B,C,E\}} {\displaystyle \{A,B,C,E\}} { D , F , G } {\displaystyle \{D,F,G\}} {\displaystyle \{D,F,G\}} に分割する分け方であり、その容量は c ( A , D ) + c ( C , D ) + c ( E , G ) = 3 + 1 + 1 = 5 {\displaystyle c(A,D)+c(C,D)+c(E,G)=3+1+1=5} {\displaystyle c(A,D)+c(C,D)+c(E,G)=3+1+1=5} である。

Javaでの実装

[編集 ]
publicclass FlowGraph{
publicstaticfinalintWHITE=0,GRAY=1,BLACK=2;
privatedouble[][]flow,capacity,resCapacity;
privateint[]parent,color,queue;
privatedouble[]minCapacity;
privateintsize,source,sink,first,last;
privatedoublemaxFlow;
publicFlowGraph(StringfileName){
// 入力テキストファイルから
// "size" 値
// "capacity[size][size]" 配列
// "source" および "sink" ノードのインデックス値(0始点)
// を読み込む。
edmondsKarp();
// 出力ファイルに結果を書く("flow" 配列と "maxFlow" 値)
}
privatevoidedmondsKarp(){// 計算量 O(V3E) のエドモンズ・カープのアルゴリズム
flow=newdouble[size][size];
resCapacity=newdouble[size][size];
parent=newint[size];
minCapacity=newdouble[size];
color=newint[size];
queue=newint[size];
for(inti=0;i<size;i++)
for(intj=0;j<size;j++)
resCapacity[i][j]=capacity[i][j];
while(BFS(source)){
maxFlow+=minCapacity[sink];
intv=sink,u;
while(v!=source){
u=parent[v];
flow[u][v]+=minCapacity[sink];
flow[v][u]-=minCapacity[sink];
resCapacity[u][v]-=minCapacity[sink];
resCapacity[v][u]+=minCapacity[sink];
v=u;
}
}
}
privatebooleanBFS(intsource){// O(V2) の幅優先探索
for(inti=0;i<size;i++){
color[i]=WHITE;
minCapacity[i]=Double.MAX_VALUE;
}
first=last=0;
queue[last++]=source;
color[source]=GRAY;
while(first!=last){// "queue" が空でないうちはループする
intv=queue[first++];
for(intu=0;u<size;u++)
if(color[u]==WHITE&&resCapacity[v][u]>0){
minCapacity[u]=Math.min(minCapacity[v],resCapacity[v][u]);
parent[u]=v;
color[u]=GRAY;
if(u==sink)returntrue;
queue[last++]=u;
}
}
returnfalse;
}
}

脚注

[編集 ]
  1. ^ E. A. Dinic (1970年). "Algorithm for solution of a problem of maximum flow in a network with power estimation". Soviet Math. Doklady (Doklady) Vol 11: 1277–1280. 
  2. ^ Jack Edmonds and Richard M. Karp (1972年). "Theoretical improvements in algorithmic efficiency for network flow problems". Journal of the ACM 19 (2): 248–264. http://www.akira.ruc.dk/~keld/teaching/algoritmedesign_f03/Artikler/08/Edmonds72.pdf . 
  3. ^ Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein (2001年). "26.2". Introduction to Algorithms (second edition ed.). MIT Press and McGraw-Hill. pp. 660-663. ISBN 0-262-53196-8  

参考文献

[編集 ]
ソート
比較ソート
線形時間ソート
並行ソート
非効率的
グラフ
探索
リスト
グラフ
文字列
最短経路問題
最小全域木
最大フロー問題
最小カット問題
線型計画問題
順序統計量
計算幾何学
種類
その他
カテゴリ
非線形(無制約)
... 関数
勾配法
収束性
準ニュートン法
その他の求解法
... ヘッセ行列
非線形(制約付き)
一般
微分可能
凸最適化
凸縮小化
線型 および
二次
内点法
ベイズ- 交換
組合せ最適化
系列範例
(Paradigms)
グラフ理論
最小全域木
最大フロー問題
メタヒューリスティクス

AltStyle によって変換されたページ (->オリジナル) /