最小コストの最倧フロヌ

茞送の問題叀兞的は、倉庫から車䞡の消費地点に商品を茞送するための最適な蚈画の問題です。

叀兞的な茞送の問題では、2぀のタむプのタスクが区別されたす。コストの基準茞送の最小コストを達成するたたは距離ず時間の基準茞送に費やされる最小時間です。

カットの䞋には倚くのテキストがありたす。 この問題を「写真で」解決するためのオプションの1぀は、 グラフにあたり慣れおいない人向けです。 添付リスト。


質問が出されたHabréず、基本的なアルゎリズムに関する蚘事が必芁かどうかに぀いお、蚘事が䜕らかの圢でスリップしたした。 リク゚ストに応答し、グラフ䞊のアルゎリズムずその実甚化に぀いお少し話すこずにしたした。 どのレベルの知識に䟝存すべきかわからなかったので、比范的耇雑で理論的に実甚的なアルゎリズムを遞択しお、蚘事が少なくずも郚分的に自然に適甚されるようにしたした。 同時に、グラフに特に粟通しおいない人にも、非垞に倚くのこずを䌝えようずしたす。

問題おずぎ話あなたは「グッズ」を生産しおいる特定の工堎の所有者であり、最近、別の郜垂にある1぀の倧䌁業ず小売ネットワヌクぞの商品の䟛絊契玄を結ぶこずができたした。 りラゞオストクでは非垞に遠いので、商品は飛行機で配送する必芁がありたす。 電話での䌚話䞭に、パヌトナヌは次のように質問したした。 「。 あなたは考えおいたした...あなたは自分のトラックトラックを茞送しおいたす。 空枯は遠いです。 茞送の蓄積された統蚈を確認した埌、茞送䞭に自分の゚リアにいく぀かの制限があるこずがわかりたした。道路には貚物怜査、重量管理のポむントがあり、䞀郚の道路は完党に修埩されおいたす。 これをすべお1日あたりの道路の「 スルヌプット 」ず呌びたす。 これらの条件に基づいお、1日あたり䜕箱の「グッズ」を空枯に茞送できるかを調べる必芁がありたす。 同時に、効果的にビゞネスを行い、最短ルヌトで商品を配送したいのは、 タむダの摩耗、メカニズム、および䞀般的な枛䟡償华費です。

合蚈ルヌトの合蚈距離を最小限に抑えながら、道路の容量を考慮しお、1日に空枯たでいく぀の箱を茞送できたすか

タスクはグラフ䞊で最も倚くなりたす。 ゜リュヌションは埐々に構築されたす。
倧きな問題はありたせん。小さな問題がたくさんありたす。 c

私がそう蚀うかもしれない堎合、アルゎリズムは、蚀う ネットにはたくさんの説明がありたす。

基本的な抂念。 カりント 男爵


この堎合のロヌドマップは、グラフの圢匏で衚瀺されたす。 頂点は亀差点であり、グラフの端は道路です。 bs骚道路には、距離次の亀差点たでず1日のスルヌプットの特性が割り圓おられたす。

コヌドでは、グラフは隣接リストたたは隣接行列の圢匏で衚されたす。 簡単にするために、隣接行列を䜿甚したす。 [u]ず[v]の亀点の隣接行列で頂点が「1」の堎合、これらの頂点亀差点ぱッゞ道路で接続されおいるこずを意味したす。 マトリックスに正確に「1」を指定する必芁はありたせん。たずえば、距離やスルヌプット同様のマトリックス内など、゚ッゞに関連する他の有甚な情報を保存するこずは非垞に䟿利です。



この図は、䞻察角線に関しお察称な行列を瀺しおいたす。 M [u] [v] = M [v] [u] これは、 無向グラフが䞎えられ、任意の方向に゚ッゞに沿っお移動できるこずを意味したす埀埩。 行列M [u] [v] = 1で、反察方向M [u] [v] = 0の堎合、グラフは方向付けられ、頂点[u]から[v]たでのみ゚ッゞに沿っお進むこずができたす。

道路の道路容量は、行列C [..] [..]に曞き蟌たれたす。これは、䞀般的には有向グラフです。 結局のずころ、「工堎」から「空枯」の方向に運転するには道路が必芁です。 指定された垯域幅プラントず空枯を持぀有向グラフは、 ネットワヌクず呌ばれたす 。

グラフが特定の特性を蚈算する必芁があるが、党䜓から倧芏暡にではなく、ある頂点から他の頂点たでの距離を想定する堎合、配列を䜿甚するず䟿利ですメモリが少なくなりたす。 ぀たり 配列dist [..]の[u]セルに、「工堎」から[u]䞊郚たでの距離を栌玍するずしたしょう。 同様に、すでに蚪れた頂点をマヌクする mark 、持っおきたボックスの数を蚘録する push 、頂点に来た堎所を蚘録する pred ために、グラフを走査するずきに配列を䜿甚したす。

わかった 玠晎らしい。 マップをグラフに倉換する方法を知っおいたす。 そしお、どうやっお空枯に箱を届けたすか 「工堎」から「空枯」ぞの道を芋぀けるこずができる必芁がありたす。 このために䜿甚したす...

幅優先怜玢アルゎリズム、BFS。


ここたでは 、垯域幅ず距離を考慮せずに、グラフの頂点の隣接関係近傍 のみを考慮したす 。

BFSは、他の倚くの基盀ずなる最も基本的なアルゎリズムの1぀です。
簡単な説明写真は䞋にありたす。 珟圚、いく぀かの開始プラントピヌク[s]に立っおいたす。そこから、゚ッゞに沿っお隣接するピヌクのみが衚瀺されたす。 そしお、できるだけ早くこのグラフのどこかにあるトップ[t]に到達する必芁がありたす。 次にこれを行いたす。 私たちは、隣人の山の端぀たり、自由な道路に沿っお芋たす。その䞭には[t]がありたす。 そうでない堎合、「最初に怜出された」すべおのネむバヌを「そこに行く必芁がある」キュヌに蚘録したす。 すべおの隣人を調べたずき-私たちはピヌクをマヌク-「すでにここにいた」。 キュヌから最初の未蚪問のピヌクを取埗し、そこに行きたす。

同じ方法で怜玢を続けたす。 同時に、䞀床蚪れたピヌクを無芖したす埌退ではありたせん。 道路で[t]に出䌚ったら-すばらしい、目暙は達成されたした

同じ亀差点に数回入らないように、それらをmark [..]配列でマヌクしたす 。 [u]ピヌクの近傍を調べた埌、 マヌク[u] = 1を配眮したした 。これは、 [u]番目の亀差点を既に「蚪問」しおいるこずを意味したす。

写真䞊郚-シリアル番号が蚘茉されおいたす



アルゎリズムを完了するず、次の図が衚瀺されたす。



䞻な機胜に泚意しおください。
これで、「トバヌ」ボックスを空枯に茞送する方法を芋぀ける方法がわかりたした。 さお...私たちはそれらを道路に沿っお連れお行き、これを地図䞊にマヌクしたす。 このマヌク-「いく぀の箱、どの道路端、どの道を進むか」を「 フロヌ 」ず呌びたす。 マトリックス フロヌ  F [..] [..]でこれに泚意したす 。 ぀たり [u]から[v ]たでの途䞭で、 F [u] [v]箱を運びたす。

珟実に出䌚う時が来たした。マトリックス 容量  C [..] [..]で瀺される「垯域幅」を考慮する必芁がありたす 。 実際、 [u]から[v]に向かう途䞭で、 C [u] [v]個の箱しか密茞できたせん。 それは残念です。

私たちは先芋の明をもっお行動したした。 BFSで「空枯」を探しおいる間、「蚪問したピヌク」をマヌクしおいる間、どの亀差点から到着したかを蚘録したした。これをpred [..]配列に蚘録したした。 ぀たり 頂点pred [v]から頂点[v]に到達したした。 そしおちょうど前に、別の䟿利な配列を開始したした push [v] 、぀たり 道路[u]-[v]に沿っお亀差点[v]にボックスをどれだけ「プッシュ」できるか。
そしお、圌らはそれを最新の状態に保ちたした push [v] = minpush [u]、C [u] [v] -F [u] [v];

このため、「空枯」から「工堎」たでの軌道を逆の順序でもう䞀床「ほどいお」、このルヌトに沿っおいく぀の箱を運ぶこずができるかを蚈算する必芁がありたす。

Push [v] = push ["airport"] = flow = here 芋぀かったパスに沿っお空枯に配達された箱の数。 すべおの゚ッゞ道路に沿っおルヌトを巻き戻し、パスのすべおの゚ッゞに「フロヌ」 フロヌを远加したす。

しかし、問題は物理的な量に関するものですが、箱の数、スルヌプット、距離など、「 マむナス 」に盎面する必芁があるかもしれたせん...

フロヌを増やすたたはFord-Fulkersonアルゎリズム


ここで、グラフの頂点の隣接近傍、゚ッゞの方向垯域幅を考慮したすが、距離はただ考慮しおいたせん。

ボックスの流れを䞊[u]から䞊[v]に増やすず、自然にF [u] [v] + = flowの操䜜を実行したすが、反察方向では、流れF [v] [u]-=フロヌ ; それが理由です。 この状況は可胜です

画像内゚ッゞ䞊-眲名枈みストリヌム/垯域幅



初めお、3぀のボックスのストリヌムを最䞊郚[i]に運び、゚ッゞ[i]-[j ]を芋぀けたした minを転送したしたプッシュ[i]、C [i] [j]-F [i] [j] = min3、3-0= 3ボックス、これをF [i] [j] + = 3ずマヌクし、反察方向にF [j] [i]-= 3を蚭定したす。

2回目は、最䞊郚[j]で自分自身を芋぀けお、 minpush [j]、C [j] [i] -F [j] [i]= min6、0--3= min 6、3 = 3から頂点[i]たで 。 ストリヌム+3に察しお-3ボックスをプッシュし、この道路に沿ったフロヌの補正を受け取りたした。 しかし、次の反埩の「空枯」の方向に、残りの3぀のボックスを远加で送信したした。

解釈倉庫[j]から倉庫[i]に電話し、「3぀の箱を自分甚に残しおください。別の甚途を芋぀けお、代わりに3぀持っおきたした。」 アルゎリズム自䜓が芪切にそれらを芋぀けたしたが。

ストリヌムの怜玢を続けたす


私たちは、成功しおいる間、「空枯」ぞの道を探し続け、それらの䞊に箱を運ぶこずに継続的に同意したした。 倧たかに蚀うず、これは最倧フロヌ怜玢アルゎリズム、たたはFord-Fulkersonアルゎリズムず呌ばれたす 。 たた、BFSを䜿甚しお新しい配信ルヌトを「開く」ため、これはEdmonds-Karpアルゎリズムず呌ばれたす。

箱を茞送しお道路を完党に「飜和」させるず、パヌトナヌに「空枯に1日䜕箱茞送できたすか」ずいう質問に答えたす。 しかし、それは圌ら自身の枛䟡償华費に぀いお考える時です...タむダ、ガ゜リン、摩耗...

BFSがグラフを怜玢するずき、距離に぀いお話しおいる堎合でも、逆流などの負の倀を凊理する必芁があるこずはすでに明らかになっおいたす「金融甚語」に結果がありたす。 䞀般に、距離をさらに考慮する時間です...

距離 ゞャック、道を進んでください


このタスクを完党に完了する時が来たしたグラフの頂点の隣接近傍、゚ッゞの指瀺されたスルヌプット、距離。

「すべおの方法で」匕き出しで道路をロヌドするたで、BFSを実行し続けたす。



では、䜕が起こったのか芋おみたしょう。 「空枯」偎から確認したす。あるボックスが15 kmの距離を超えお到着した堎合、぀たり拒吊した堎合は15 km節玄できたす。 旅行぀たり、15を匕くが、別の移動方法を芋぀けるアタッチする必芁がありたす。

「空枯」から前方自由道路ず埌方抌し戻しお保存のin骚に沿っお歩いおみたしょう。

画像゚ッゞ-笊号付きフロヌ/スルヌプット、および䞊-距離



䞊の図では、「負のサむクル」-6が芋぀かりたしたが、ただ利甚可胜なフリヌたたは䞊流のリブに沿っお歩き続けおいたす。 その䞭で1回転するこずで、それに参加する頂点の距離を-6枛らすこずができたす。 これは、サむクルで茞送される箱の配送を節玄できるこずを意味したす。 箱を「ルヌプに入れる」だけです。 䞊の写真では、6 km節玄できたす。 方法。

これで問題の解決方法がわかりたしたが、これらのサむクルを怜出するために...

ベルマンフォヌドアルゎリズム


頂点[s]から残りの頂点たでの最短距離を芋぀けるために䜿甚されたす。 しかし、BFSずは異なり、短いパスはこのパスに沿ったグラフの゚ッゞの数ずいう意味ではなく、パスの゚ッゞに沿った「距離」の合蚈ずいう意味になりたす。

ただし、これには必芁ありたせん。 これをダむクストラアルゎリズムず区別する䞻な機胜の1぀は、゚ッゞの重みを負の数で指定できるグラフで機胜するこずです。 アルゎリズムは、このようなグラフの副䜜甚、぀たり負の倀のサむクルを怜出できたす。 必芁なもの

アルゎリズムはやや耇雑です。 この実装は、Cormenの聖曞ずは関係ありたせんが、うたく機胜したす。 芋た目は、BFSに倚少䌌おいるため、説明を始めようず思いたす。

特定の頂点から開始し、「アクセス可胜な」゚ッゞに沿っお隣接する頂点を芋お、 dist [..]配列でそれらの距離を改善し、可胜な限り小さくしたす。 このプロセスは「緩和」ず呌ばれたす。 そのような頂点を゚ッゞに沿っお「発芋」した堎合、頂点たでの距離を曎新し、それらの頂点を「それらからのグラフを改善しおみおください」キュヌに入れたす。 BFSに非垞に䌌おいたす ただし、ピヌクをマヌクしたせん「既に蚪れた」。同じピヌクに2回行かなければならない堎合は、それを行いたす。

しかし、問題は、ピヌクたでの距離を瞮め、氞遠にスピンできる「負のサむクル」があるずいう事実に備えおいたすか プロセスは終了したせん。 したがっお、頂点の「怜査半埄」は、数N 頂点自䜓の数によっお制限されたす。 これは、任意の頂点たでの最小距離を蚈算するために十分に保蚌され、最も重芁なこずには、アルゎリズムはいずれの堎合でも終了したす。

これを行うには、最初の頂点をキュヌに入れ、その埌に「スタブ」を眮きたす。これにより、キュヌ内の頂点が「怜査半埄0」にあるこずを瀺したす。 キュヌから次のピヌクを取り出すず、突然「プラグ」を取埗したす。次の「怜査半埄」を瀺す新しいプラグを配眮したす。 ここに、䞀般に、アルゎリズムの党䜓のロゞックがありたす。 =

ピヌクたでの距離の改善は、次の䞍等匏によっお怜蚌されたす。
dist [v]> dist [u] + edge_costu、v

写真゚ッゞ䞊-長さ、およびツヌルチップ-珟時点で芋぀かった最短距離



䞻な機胜に泚意しおくださいBFSずは異なりたす。
「半埄N頂点の数」でグラフを衚瀺するず、すべおの頂点に぀いお最小距離が怜出されたす。 そしお、これ以䞊枛らすものはありたせん。 たた、ピヌクの䞀郚が「負のサむクル」に「匕き蟌たれる」堎合、平等違反をチェックするこずで簡単に怜出できたす。 実際、サむクルでは、距離は無限に枛少したす。
dist [v]> dist [u] + edge_costu、v

したがっお、頂点[v]に察しおこの䞍等匏が成り立぀堎合、負のサむクルに参加するこずを意味したす。 必芁なもの 私たちがそれに沿った道を圌女から「巻き戻し」、私たちは圌女のサむクルに沿っお回転したす。

すべお-サむクルが発芋されたした 残っおいるのは、ボックスの流れを「埌方」に向けるこずです。これにより、ビゞネスの効率が向䞊したす。

最小コスト最倧フロヌアルゎリズム




それだけです パヌトナヌに電話しお、1日に配達できる商品の数をお知らせしたす。 そしお、節玄したお金をどのように適甚するかを考えたす。 =

int C[MAX_N][MAX_N]; // " "
int F[MAX_N][MAX_N]; // " "
int P[MAX_N][MAX_N]; // " ()"
int push[MAX_N]; // [v]
int mark[MAX_N]; // ,
int pred[MAX_N]; // [v] ()
int dist[MAX_N]; // [v]
int N, M, s ,t; // - , ,
int max_flow;
int min_cost;

void file_read()
{
int u, v, c, p;
in >> N >> M >> s >> t; N++;

for ( int i = 0; i < M; i++)
{
in >> u >> v >> c >> p;
C[u][v] = c;
P[u][v] = p;
P[v][u] = -p;
}
}

int edge_cost( int u, int v)
{
if ( C[u][v] - F[u][v] > 0 ) return P[u][v];
else return MAX_VAL;
}

int check_cycles()
{
for ( int u = 1; u < N; u++)
for ( int v = 1; v < N; v++)
if ( dist[v] > dist[u] + edge_cost(u, v) )
return u;

return MAX_VAL;
}

void init()
{
for ( int i = 1; i < N; i++)
{
mark[i] = 0;
push[i] = 0;
pred[i] = 0;
dist[i] = MAX_VAL;
}
}

//

int bf( int s)
{
init();
queue< int > Q;
pred[s] = s;
dist[s] = 0;

Q.push(s);
Q.push(MAX_N);

int u, series = 0;
while ( !Q.empty() )
{
while ( Q.front() == MAX_N )
{
Q.pop();
if ( ++series > N ) return check_cycles();
else Q.push(MAX_N);
}

u = Q.front(); Q.pop();
for ( int v = 1; v < N; v++)
if ( dist[v] > dist[u] + edge_cost(u, v) )
{
dist[v] = dist[u] + edge_cost(u, v);
pred[v] = u;
Q.push(v);
}
}
}

// -

int bfs( int s, int t)
{
init();
queue< int > Q;
mark[s] = 1;
pred[s] = s;
push[s] = MAX_VAL;

Q.push(s);
while ( !mark[t] && !Q.empty() )
{
int u = Q.front(); Q.pop();
for ( int v = 1; v < N; v++)
if ( !mark[v] && (C[u][v]-F[u][v] > 0) )
{
push[v] = min(push[u], C[u][v]-F[u][v]);
mark[v] = 1;
pred[v] = u;
Q.push(v);
}
}

return mark[t];
}

// -

void max_flow_ff()
{
int u, v, flow = 0;

while ( bfs(s, t) )
{
int add = push[t];

v = t; u = pred[v];
while ( v != s )
{
F[u][v] += add;
F[v][u] -= add;
v = u; u = pred[v];
}
flow += add;
}

max_flow = flow;
}

//

void min_cost_flow()
{
max_flow_ff();

int u, v, flow = 0;
int add = MAX_VAL;
int neg_cycle;

neg_cycle = bf(t);
while ( neg_cycle != MAX_VAL )
{
v = neg_cycle; u = pred[v];
do
{
add = min(add, C[u][v]-F[u][v]);
v = u; u = pred[v];
}
while ( v != neg_cycle );

v = neg_cycle; u = pred[v];
do
{
F[u][v] += add;
F[v][u] -= add;
v = u; u = pred[v];
}
while ( v != neg_cycle );

neg_cycle = bf(t);
}

for ( int u = 1; u < N; u++)
for ( int v = 1; v < N; v++)
if ( F[u][v] > 0 )
min_cost += F[u][v] * P[u][v];
}

void file_write()
{
out << max_flow << endl;
out << min_cost << endl;
}

void main()
{
file_read();
min_cost_flow();
file_write();
}


* This source code was highlighted with Source Code Highlighter .


//そしお、このような条件を採甚した堎合ピヌク-道路の亀差点、゚ッゞ-道路、スルヌプット-車線の数蚱容速床などからこれらの道路の珟圚の車の数を匕いたもの。 「A」通りから「B」通りぞの最倧の流れを芋぀けたす-垂内で珟圚無料ではない道路は䜕ですか もちろん、もっず倚くのパラメヌタヌを考慮する必芁がありたすが、基本はグラフです。 これは面癜いです。 =

合蚈


あたりscられないでください

グラフに぀いおの投皿を始めたずき、私はどのレベルの胜力に頌るべきかわかりたせんでした。これたでのずころ、たずえば、ダむクストラに぀いおは話さないこずにしたした。 突然、1秒ごずに暗蚘したす。 しかし、Habr仲間がこれらのアルゎリズムの実甚的な偎面に興味を持っおいたこずは確かに芚えおいたす。 したがっお、圌は「球圢」問題を取り䞊げ、その甚語でグラフに぀いお明確に䌝えようずしたした。

誰かがグラフずその応甚䟋に぀いお興味を持っおくれるこずを願っおいたす。 さらに、最も有名なプログラミングオリンピックACM ICPCの 1぀に぀いお、孊生孊童たたはプログラミングを教える倧孊院生に思い出させるために蚘事を曞くよう促されたした 倧孊の初期にただ決たっおいないあえおしなかった人のために、チヌムを線成し、コンピュヌタクラスで遅くたで起き、アルゎリズムの挞近的挙動に぀いお議論し、それらの解決策ず反䟋を考え出す。 アルゎリズムは興味深いものであり、䞀緒に集たる正圓な理由であり、チヌムプレむの経隓は貎重です。 今すぐ参加しよう

Source: https://habr.com/ru/post/J61884/


All Articles