Zaawansowane algorytmy i struktury danych/Wykład 10: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Sank (dyskusja | edycje)
m Zastępowanie tekstu – „.</math>” na „</math>”
 
(Nie pokazano 21 wersji utworzonych przez 3 użytkowników)
Linia 1: Linia 1:
== Abstrakt ==
== Abstrakt ==


W wykładzie tym przedstawimy trzy algorytmy znajdowania przepływu w grafie.  
W wykładzie tym przedstawimy trzy algorytmy znajdowania przepływu w grafie. Pierwszym będzie algorytm Edmondsa-Karpa działający w czasie <math>O(nm^2)</math>. Następnym będzie algorytm Dinica działający w czasie <math>O(n^2 m)</math>, oraz trzecim tak zwany algorytm trzech Hindusów, działający w czasie <math>O(n^3)</math>. Nazwiska tych tytułowych Hindusów to Malhotra, Kumar i Maheshwari. Dwa ostatnie algorytmy oparte będą na konstrukcji przepływów blokujących, które są analogiczną konstrukcją do konstrukcji maksymalnego zbioru rozłącznych ścieżek, której użyliśmy w [[../Wykład 7#algorytm_hopcrofta-karpa|algorytmie Hopcrofta-Karpa]].
Pierwszym będzie algorytm Edmondsa-Karpa działający w czasie <math>O(nm^2)</math>. Następnym będzie algorytm Dinica działający w czasie <math>O(n^2 m)</math>, oraz trzecim tak zwany algorytm trzech Hindusów działający w czasie <math>O(n^3)</math>. Nazwiska tych tytułowych Hindusów to Malhotra, Kumar i Maheshwari. Te dwa ostatnie algorytmy oparte będą na konstrukcji przepływów blokujących, które są analogiczną konstrukcją do konstrukcji maksymalnego zbioru rozłącznych ścieżek, której użyliśmy w [[../Wykład 7#algorytm_hopcrofta-karpa|algorytmie Hopcrofta-Karpa]].


== Algorytm Edmonds’a-Karp’a ==
== Algorytm Edmonds’a-Karp’a ==


Ograniczenie w czasie działania w algorytmie Forda–Fulkersona może zostać poprawione, kiedy jako ścieżkę powiększającą będziemy wybierać zawsze najkrótsza ścieżkę z <math>s</math> do <math>t</math> w sieci rezydualnej,  przy założeniu gdzie każda krawędź ma jednostkową wagę. Teraz udowodnimy, że algorytm Edmonds’a–Karp’a działa w czasie <math>O(nm^2)</math>. W naszej analizie użyjemy odległości do wierzchołków w sieci rezydualnej <math>G_f</math>. Poniższy lemat korzysta z zapisu <math>d_f (u, v)</math> dla odległości <math>u</math> do <math>v</math> w <math>G_f</math>, gdzie każdąa krawędź ma jednostkową wagę.
Algorytm Edmonds'a-Karp'a to algorytm Forda-Fulkersona w, którym zamiast dowolnej ścieżki powiększającej wybieramy zawsze najkrótszą ścieżkę powiększającą. Zakładamy tutaj, że wszystkie krawędzie mają jednostkowe długości. Taka modyfikacja pozwala poprawić ograniczenie w czasie działania tego algorytmu. Udowodnimy, że algorytm Edmonds’a–Karp’a działa w czasie <math>O(nm^2)</math>. W naszej analizie będziemy korzystać z zapisu <math>d_f (u, v)</math> dla odległości z <math>u</math> do <math>v</math> w <math>G_f</math>, przy założenie, że każda krawędź ma jednostkową wagę.


{{lemat|1|lemat_1|3=
{{lemat|1|lemat_1|3=
Jeśli algorytm Edmonds’a – Karp’a działa w sieci przepływowej <math>G = (V, E)</math> ze źródłem <math>s</math> i ujściem <math>t</math>, to wtedy dla wszystkich wierzchołków <math>v \in V - \{s, t\}</math>, to odległość <math>d_f (s, v)</math> w sieci rezydualnej <math>G_f</math> wzrasta monotonicznie z każdym powiększeniem przepływu.
Jeśli algorytm Edmondsa–Karpa działa w sieci przepływowej <math>G = (V, E)</math> ze źródłem <math>s</math> i ujściem <math>t</math>, to wtedy dla wszystkich wierzchołków <math>v \in V - \{s, t\}</math>, odległość <math>d_f (s, v)</math> w sieci rezydualnej <math>G_f</math> nie maleje.
}}
}}


{{Dowod|||3=Przypuśćmy, że dla pewnego wierzchołka <math>v \in V - \{s, t\}</math>, istnieje powiększający przepływ, który powoduje, że zmniejszenie odległości najkrótszej ścieżki z <math>s</math> do <math>v</math>, a następnie otrzymamy wynik sprzeczny z tym założeniem. Nich <math>f</math> będzie przepływem zaraz przed pierwszym powiększeniem, które skraca długość najkrótszej ścieżki i niech <math>f'</math> będzie przepływem następującym zaraz potem. Nich <math>v</math> będzie wierzchołkiem o minimalnym <math>d_{f'}(s, v)</math>, którego dystans został zmniejszony poprzez to powiększenie tak, że <math>d_{f'}(s, v) < d_f(s, v)</math>. Nich <math>p = s \to u to \v</math> będzie najkrótszą ścieżką <math>s</math> do <math>v</math> w <math>G_{f'}</math>, tak że <math>(u, v) \in E_{f'}</math>  oraz:
{{Dowod|||3=Przypuśćmy, że dla pewnego wierzchołka <math>v \in V - \{s, t\}</math> istnieje powiększający przepływ, który powoduje zmniejszenie odległości najkrótszej ścieżki z <math>s</math> do <math>v</math>, a następnie otrzymamy wynik sprzeczny z tym założeniem. Niech <math>f</math> będzie przepływem zaraz przed pierwszym powiększeniem, które skraca długość najkrótszej ścieżki i niech <math>f'</math> będzie przepływem następującym zaraz potem. Niech <math>v</math> będzie wierzchołkiem o minimalnym <math>d_{f'}(s, v)</math>, którego dystans został zmniejszony poprzez to powiększenie tak, że <math>d_{f'}(s, v) < d_f(s, v)</math>. Niech <math>p = s \to u \to v</math> będzie najkrótszą ścieżką z <math>s</math> do <math>v</math> w <math>G_{f'}</math>, tak że <math>(u, v) \in E_{f'}</math>  oraz:


{{wzor2|1=
{{wzor2|1=
<math>d_{f'}(s,u) = d_{f'}(s,v) -1.</math>
<math>d_{f'}(s,u) = d_{f'}(s,v) -1</math>
}}
}}


Ze względu na sposób wybrania <math>v</math>, wiemy ze odległość z wierzchołka <math>u</math> się nie zmniejszyła, to znaczy:
Ze względu na sposób wybrania <math>v</math>, wiemy że odległość z wierzchołka <math>u</math> się nie zmniejszyła, to znaczy:


{{wzor2|1=
{{wzor2|1=
<math>d_{f'}(s,u) \ge d_{f}(s,u).</math>
<math>d_{f'}(s,u) \ge d_{f}(s,u)</math>
}}
}}


Twierdzimy, że <math>(u, v) \notin E_f</math>. Dlaczego? Gdybyśmy mieli <math>(u, v) \in E_f</math>, wówczas byśmy również mieli z nierówności trujkąta dla <math>s,v</math> i <math>u</math> oraz powyższych nierówności:  
Twierdzimy, że <math>(u, v) \notin E_f</math>. Dlaczego? Gdybyśmy mieli <math>(u, v) \in E_f</math>, wówczas z nierówności trójkąta dla <math>s,v</math> i <math>u</math> oraz powyższych nierówności wynikałoby:  


{{wzor2|1=
{{wzor2|1=
<math>d_f(s, v) \le d_f(s, u) + 1 \le  d_{f'} (s, u) + 1 \le  d_{f'} (s, v),</math>
<math>d_f(s, v) \le d_f(s, u) + 1 \le  d_{f'} (s, u) + 1 \le  d_{f'} (s, v)</math>
}}
}}


Co jest sprzeczna z naszym założeniem, że <math>d_{f'}(s, v) < d_f(s, v)</math>. Jak możemy zatem otrzymać <math>(u, v) \notin E_f</math>  i <math>(u, v) \in E_{f'}</math>? W powiększeniu przepływu z <math>f</math> do <math>f'</math> powinien być powiększony przepływ z <math>v</math> do <math>u</math>. Algorytm Edmonds’a–Karp’a zawsze powiększa przepływ wzdłuż najkrótszych ścieżek, i dlatego też najkrótsza ścieżka z <math>s</math> do <math>u</math> w <math>G_f</math> posiada <math>(v, u)</math> jako ostatnią krawędź. Dlatego mamy:
Co jest sprzeczne z założeniem, że <math>d_{f'}(s, v) < d_f(s, v)</math>. Jak możemy zatem otrzymać <math>(u, v) \notin E_f</math>  i <math>(u, v) \in E_{f'}</math>? Powiększeniu przepływu z <math>f</math> do <math>f'</math> powinno także powiększyć przepływ z <math>v</math> do <math>u</math>. Algorytm Edmondsa–Karpa zawsze powiększa przepływ wzdłuż najkrótszych ścieżek i dlatego też najkrótsza ścieżka z <math>s</math> do <math>u</math> w <math>G_f</math> posiada <math>(v, u)</math> jako ostatnią krawędź. Dlatego mamy:


{{wzor2|1=
{{wzor2|1=
<math>d_f(s, v) = d_f(s, u) 1 = d_{f'} (s, u) - 2  = d_{f'} (s, v) - 2,</math>
<math>d_f(s, v) = d_f (s, u) - 1 = d_{f'} (s, u) - 2  = d_{f'} (s, v) - 2</math>
}}
}}


co jest sprzeczne z naszym założeniem, że <math>d_{f'} (s, v) < d_f(s, v)</math>. Wnioskujemy, że nasze założenie, iż taki wierzchołek <math>v</math> istnieje jest nieprawdziwe.
co jest sprzeczne z założeniem, że <math>d_{f'} (s, v) < d_f(s, v)</math>. Wnioskujemy zatem, że założenie, iż taki wierzchołek <math>v</math> istnieje, jest nieprawdziwe.
}}
}}


Następne twierdzenie ogranicza liczbę iteracji algorytmu Edmonds’a–Karp’a.
Następujące twierdzenie ogranicza liczbę iteracji algorytmu Edmondsa–Karpa.


{{twierdzenie|2|twierdzenie_2|3=
{{twierdzenie|2|twierdzenie_2|3=
Jeśli algorytm Edmonds’a–Karp’a działa w sieci przepływowej <math>G = (V, E)</math> ze źródłem <math>s</math> i ujściem <math>t</math>, wówczas całkowita liczba przepływów powiększających znalezionych w algorytmie wynosi <math>O(V E)</math>.
Jeśli algorytm Edmondsa–Karpa działa w sieci przepływowej <math>G = (V, E)</math> ze źródłem <math>s</math> i ujściem <math>t</math>, wówczas całkowita liczba przepływów powiększających znalezionych w algorytmie wynosi <math>O(V E)</math>.
}}
}}


{{dowod|||3=
{{dowod|||3=
Mówimy, że krawędź <math>(u, v)</math> w sieci rezydualnej <math>G_f</math> jest '''krytyczna''' na ścieżce powiększającej <math>p</math> jeśli przepustowość rezydualna <math>p</math> jest przepustowością rezydualną <math>(u, v)</math>, to znaczy jeśli <math>c_f(p) = c_f(u, v)</math>. Po tym jak otrzymamy powiększający przepływ wzdłuż ścieżki powiększającej, każda krawędź krytyczna na ścieżce znika z sieci rezydualnej. Ponadto, co najmniej jedna krawędź na dowolnej ścieżce musi być krytyczna. Pokażemy, ze każda z <math>|E| </math>krawędzi może stać się krytyczna co najwięcej <math>|V|/2 1</math> razy.
Mówimy, że krawędź <math>(u, v)</math> w sieci rezydualnej <math>G_f</math> jest '''krytyczna''' na ścieżce powiększającej <math>p</math>, jeśli przepustowość rezydualna <math>p</math> jest przepustowością rezydualną <math>(u, v)</math>, to znaczy jeśli <math>c_f(p) = c_f(u, v)</math>. Po tym, jak otrzymamy powiększający przepływ wzdłuż ścieżki powiększającej, każda krawędź krytyczna na ścieżce znika z sieci rezydualnej. Ponadto co najmniej jedna krawędź na dowolnej ścieżce musi być krytyczna. Pokażemy, że każda z <math>|E|</math>krawędzi może stać się krytyczna co najwyżej <math>|V|/2 - 1</math> razy.


Niech <math>u</math> i <math>v</math> będą wierzchołkami w <math>V</math> połączonymi krawędzią <math>E</math>. Ponieważ ścieżki powiększające są krótszymi ścieżkami, kiedy <math>(u,v)</math> są krytyczne za pierwszym razem, otrzymujemy
Niech <math>u</math> i <math>v</math> będą wierzchołkami w <math>V</math> połączonymi krawędzią <math>E</math>. Ponieważ ścieżki powiększające są najkrótszymi ścieżkami, to dla kawędzi krytycznej <math>(u,v)</math>, otrzymujemy


{{wzor2|1=
{{wzor2|1=
<math>d_f(s, v) = d_f (s, u) + 1.</math>
<math>d_f(s, v) = d_f (s, u) + 1</math>
}}
}}


Jak tylko przepływ jest zwiększony, krawędź <math>(u, v)</math> znika z sieci rezydualnej. Nie może ona się znów pojawić na żadnej innej ścieżce powiększającej dopuki jak przepływ z <math>u</math> do <math>v</math> nie będzie zmniejszony, a to nastąpi tylko wtedy, kiedy <math>(v, u)</math> pojawi się na ścieżce powiększającej. Jeśli <math>f'</math> jest przepływem w <math>G</math> i to zdarzenie ma miejsce, wówczas mamy:
Gdy tylko przepływ jest zwiększony, krawędź <math>(u, v)</math> znika z sieci rezydualnej. Nie może ona się znów pojawić na żadnej innej ścieżce powiększającej dopóki przepływ z <math>u</math> do <math>v</math> nie będzie zmniejszony, a nastąpi to tylko wtedy, kiedy <math>(v, u)</math> pojawi się na ścieżce powiększającej. Jeśli <math>f'</math> jest przepływem w <math>G</math> i to zdarzenie ma miejsce, wówczas mamy:


{{wzor2|1=
{{wzor2|1=
<math>d_{f'}(s, u) = d_{f'}(s, v) + 1.</math>
<math>d_{f'}(s, u) = d_{f'}(s, v) + 1</math>
}}
}}


Ponieważ  <math>d_f(s, v) = d_{f'}(s, v)</math>, co wynika z [[#lemat_1|lematu 1]], otrzymujemy
Ponieważ  <math>d_f(s, v) \le d_{f'}(s, v)</math>, co wynika z [[#lemat_1|lematu 1]], otrzymujemy


{{wzor2|1=
{{wzor2|1=
<math>d_{f'}(s, u) = d_{f'}(s, v) + 1 = d_f(s, v) + 1 = d_f(s, u) + 2.</math>
<math>d_{f'}(s, u) = d_{f'}(s, v) + 1 \ge d_f(s, v) + 1 = d_f(s, u) + 2</math>
}}
}}


Czyli, od czasu kiedy <math>(u, v)</math> staje sie krytyczne do czasu kiedy ponownie staje się krytyczne, dystans <math>u</math> ze źródła zwiększą się o co najmniej <math>2</math>. Dystans <math>u</math> ze źródła wynosi początkowo, co najmniej <math>0</math>. Wierzchołki pośrednie (intermediate) na najkrótszej ścieżce z <math>s</math> do <math>u</math> nie mogą zawierać <math>s</math>, <math>u</math> ani <math>t</math>, (ponieważ to, że <math>(u, v)</math> jest  krytyczna na ścieżce oznacza, że istnieje ścieżka z <math>u</math> do <math>t</math>). Dlatego tez zanim <math>u</math> stanie się nieosiągalne ze źródła, jeśli kiedykolwiek, jego odległość do niego wynosić będzie co najwyżej <math>|V| - 2</math>. Stąd, <math>(u, v)</math> może stać sie krytyczne co najwyżej <math>(|V|-2)/2 = |V|/2-1</math> razy. Ponieważ istnieje <math>O(|E|)</math> par wierzchołków które mogą mieć krawędź pomiędzy sobą w grafie rezydualnym, całkowita liczba krawędzi krytycznych podczas działania algorytmu Edmonds’a–Karp’a wynosi <math>O(|V| |E|)</math>, bo każda ścieżka powiększająca ma co najmniej jedna krawędź krytyczną.
Czyli od czasu, kiedy <math>(u, v)</math> stało sie krytyczne, do czasu kiedy ponownie stanie się krytyczne, dystans ze źródła do <math>u</math> zwiększa się o co najmniej <math>2</math>. Dystans do <math>u</math> wynosi początkowo co najmniej <math>0</math>. Wierzchołki pośrednie na najkrótszej ścieżce z <math>s</math> do <math>u</math> nie mogą zawierać <math>s</math>, <math>u</math> ani <math>t</math> (ponieważ to, że <math>(u, v)</math> jest  krytyczna oznacza, że <math>u \neq t</math>). Dlatego też odległość do <math>u</math> może wynosić co najwyżej <math>|V| - 2</math>. Stąd <math>(u, v)</math> może stać sie krytyczne co najwyżej <math>(|V|-2)/2 = |V|/2-1</math> razy. Ponieważ istnieje <math>O(|E|)</math> par wierzchołków pomiędzy którymi może istnieć krawędź w grafie rezydualnym, to całkowita liczba krawędzi krytycznych podczas działania algorytmu Edmondsa–Karpa wynosi <math>O(|V| |E|)</math>, bo każda ścieżka powiększająca ma co najmniej jedną krawędź krytyczną.
}}
}}


Ponieważ każdą iteracje algorytmu FORD-FULKERSON można zaimplementować w czasie <math>O(|E|)</math>, to całkowity czas działania algorytmu Edmonds'a-Karp'a wynosi <math>O(|V| |E|^22)</math>. W następnych części wykładu pokażemy jak wykorzystując przepływy blokujące poprawić ten wynik do czasu <math>O(|V|^3)</math>.
Ponieważ każdą iterację algorytmu FORD-FULKERSON można zaimplementować w czasie <math>O(|E|)</math>, to całkowity czas działania algorytmu Edmondsa-Karpa wynosi <math>O(|V| |E|^2)</math>. W następnych częściach wykładu pokażemy, jak wykorzystując przepływy blokujące poprawić ten wynik do czasu <math>O(|V|^3)</math>.


== Przepływ blokujący ==
== Przepływ blokujący ==


'''Przepływem blokującym''' w sieci rezydualnej <math>G_f</math> nazywamy taki przepływ <math>b</math> w <math>G_f</math>, że:
'''Przepływem blokującym''' w sieci rezydualnej <math>G_f</math> nazywamy taki przepływ <math>b</math> w <math>G_f</math>, że:{{kotwica|warunki_blokujace}}
# każda ścieżka z <math>s</math> do <math>t</math> w <math>b</math> jest najkrótszą ścieżką w <math>G_d</math>,
# każda ścieżka z <math>s</math> do <math>t</math> w <math>b</math> jest najkrótszą ścieżką w <math>G_f</math>,
# oraz każda najkrótsza ścieżka w <math>G_f</math> zawiera krawędź nasyconą w <math>G_{f+b}</math>.
# oraz każda najkrótsza ścieżka w <math>G_f</math> zawiera krawędź nasyconą w <math>G_{f+b}</math>.


Zauważ, że jest to definicja która odpowiada pojęciu maksymalnego zbioru najkrótszych ścieżek powiększających użytemu w [[../Wykład 7#max_sieżki|Wykładzie 7]]. Załóżmy, na chwile, że mamy algorytm znajdujący przepływ blokujący, pokażemy jak go wykorzystać do znalezienia przepływu maksymalnego w algorytmie Dinica. Algorytmy na znajdowanie przepływu blokującego pokażemy w dalszej części tego wykładu.
Zauważ, że jest to definicja, która odpowiada pojęciu maksymalnego zbioru najkrótszych ścieżek powiększających użytemu w [[../Wykład 7#max_sieżki|Wykładzie 7]]. Załóżmy na chwilę, że mamy algorytm znajdujący przepływ blokujący. Pokażemy jak go wykorzystać do znalezienia przepływu maksymalnego, jest to algorytm Dinica. Algorytmy na znajdowanie przepływu blokującego pokażemy w dalszej części tego wykładu.


{{algorytm|[Dinica] znajduje przepływ maksymalny w grafie <math>G</math>|algorytm_Dinica|
{{algorytm|[Dinica] znajduje przepływ maksymalny w grafie <math>G</math>|algorytm_Dinica|
3=
3=
   DINIC(G, s, t)
   DINIC<math>(G, s, t)</math>
   1  <math>f = 0</math>
   1  <math>f = 0</math>
   2  '''while''' istnieje ścieżka od <math>s</math> do <math>t</math> w <math>G_f</math> '''do'''
   2  '''while''' istnieje ścieżka od <math>s</math> do <math>t</math> w <math>G_f</math> '''do'''
Linia 91: Linia 90:
}}
}}


Poprawność algorytmu Dinica wynika bezpośrednio z [[../Wykład 9#twierdznie_5|twierdzenia o maksymalnym przepływie i minimalnym przekroju]], gdyż po zakończeniu algorytmu nie ma już w sieci <math>G</math> ścieżek powiększających. Zastanówmy się teraz ile razy może zostać wykonana pętla '''while''', czyli innymi słowy ile razy będzie konieczne znajdowanie przepływu blokującego.
Poprawność algorytmu Dinica wynika bezpośrednio z [[../Wykład 9#twierdznie_5|twierdzenia o maksymalnym przepływie i minimalnym przekroju]], gdyż po zakończeniu algorytmu nie ma już w sieci <math>G</math> ścieżek powiększających. Zastanówmy się teraz, ile razy może zostać wykonana pętla '''while''', czyli innymi słowy ile razy będzie konieczne znalezienie przepływu blokującego.


{{lemat|3|lemat 3|3=
{{lemat|3|lemat 3|3=
Linia 98: Linia 97:


{{dowod|||3=
{{dowod|||3=
Załóżmy, że długość najkrótszej ścieżki <math>p</math> w <math>G_{f+b}</math> jest nie większa niż długość najkrótszej ścieżki w <math>G_f</math>. Wtedy ścieżka <math>p</math> ma z przepływem blokującym <math>b</math> wspólną krawędź nasyconą. Niech <math>u-v</math> będzie ostatnią taką krawędzią na <math>p</math>. Oznacza to, że krawędź <math>v-u</math> musiała należeć do przepływu <math>b</math>. Inaczej w <math>G_{f+b}</math> <math>u-v</math> nadal byłaby nasycona. Ponieważ <math>b</math> może zostać rozłożone na sumę pewnych najkrótszych ścieżek w <math>G_f</math>, to z [[#lemat_1|lematu 1]], wiemy, że odległość z <math>s</math> do <math>u</math> nie zmalała, tzn. <math>d_{f}(s,u) \le d_{f+b}(s,u)</math>. Jednak ponieważ <math>p</math> jest najkrótszą ścieżką z <math>s</math> do <math>t</math>, to oznacza, że odległość do <math>v</math> wzrosła o co najmniej <math>2</math>, <math>d_{f}(s,v) +2 \le d_{f+b}(s,v)</math>. Kawałek ścieżki <math>p</math> od <math>v</math> do <math>t</math> też jest najkrótszą ścieżką, więc <math>d_{f}(s,t) +2 \le d_{f+b}(s,t)</math>. Długość najkrótszej ścieżki w grafie rezydualnym musiała więc wzrosnąć.
Załóżmy, że długość najkrótszej ścieżki <math>p</math> w <math>G_{f+b}</math> jest nie większa niż długość najkrótszej ścieżki w <math>G_f</math>. Wtedy ścieżka <math>p</math> ma z przepływem blokującym <math>b</math> wspólną krawędź nasyconą. Niech <math>u-v</math> będzie ostatnią taką krawędzią na <math>p</math>. Oznacza to, że krawędź <math>v-u</math> musiała należeć do przepływu <math>b</math>. Inaczej w <math>G_{f+b}</math> krawędź <math>u-v</math> nadal byłaby nasycona. Ponieważ <math>b</math> może zostać rozłożone na sumę pewnych najkrótszych ścieżek w <math>G_f</math>, to z [[#lemat_1|lematu 1]], wiemy, że odległość z <math>s</math> do <math>u</math> nie zmalała, tzn. <math>d_{f}(s,u) \le d_{f+b}(s,u)</math>. Jednak ponieważ <math>p</math> jest najkrótszą ścieżką z <math>s</math> do <math>t</math>, oznacza to, że odległość do <math>v</math> wzrosła o co najmniej <math>2</math>, <math>d_{f}(s,v) +2 \le d_{f+b}(s,v)</math>. Kawałek ścieżki <math>p</math> od <math>v</math> do <math>t</math> też jest najkrótszą ścieżką, więc <math>d_{f}(s,t) +2 \le d_{f+b}(s,t)</math>. Długość najkrótszej ścieżki w grafie rezydualnym musiała więc wzrosnąć.
}}
}}


{{wniosek|4|wniosek_4|3=
{{wniosek|4|wniosek_4|3=
Ponieważ maksymalna długość najkrótszej ścieżki może wynosić co najwyżej <math>n-1</math>, więc maksymalna liczba faz w algorytmie Dinica wynosi <math>n</math>.
Ponieważ maksymalna długość najkrótszej ścieżki może wynosić co najwyżej <math>n-1</math>, maksymalna liczba faz w algorytmie Dinica wynosi <math>n</math>.
}}
}}


== Znajdowanie przepływu blokującego - Algorytm Dinica ==
== Znajdowanie przepływu blokującego - Algorytm Dinica ==


Zanim przejdziemy do algorytmów znajdujących przepływ blokujących wprowadźmy pojęcie sieci warstwowej. '''Sieć warstwową''' <math>\overline{G}_f</math> dla sieci rezydualnej <math>G_f = (V,E_f)</math> definiujemy jako graf skierowany <math>\overline{G}_f = (V,\overline{E}_f)</math> o następującym zbiorze krawędzi:
Zanim przejdziemy do opisu algorytmów znajdujących przepływ blokujący, wprowadźmy pojęcie sieci warstwowej. '''Sieć warstwową''' <math>\overline{G}_f</math> dla sieci rezydualnej <math>G_f = (V,E_f)</math> definiujemy jako graf skierowany <math>\overline{G}_f = (V,\overline{E}_f)</math> o następującym zbiorze krawędzi:


{{wzor2|1=
{{wzor2|1=
<math>
<math>
\overline{E}_M = \{(u,v): (u,v) \in E_f \mbox{ i } d_f(s,u) + 1 = d_f(s,v)\}.
\overline{E}_f = \{(u,v): (u,v) \in E_f \mbox{ i } d_f(s,u) + 1 = d_f(s,v)\}.
</math>
</math>
}}
}}


Zauważmy, że wszystkie ścieżki w <math>\overline{G}_f</math> z <math>s</math> do <math>t</math> są najkrótszymi ścieżkami. Jeżeli chcemy wyszukać przepływ blokujący, to zauważmy, że robiąc to w sieci warstwowej będziemy mieli spełniony automatycznie warunek 1 definicji przepływu blokującego. W grafie <math>\overline{G}_f</math> wszystkie ścieżki są najkrótsze, jednak nie wszystkie ścieżki muszą prowadzić do <math>t</math>. Jeżeli usuniemy za w czasu z grafu <math>\oveline{G}_f</math> krawędzie które prowadzą do nikąd, to ścieżki z <math>s</math> do <math>t</math> będziemy mogli wyszukiwać w czasie <math>O(n)</math>.
Zauważmy, że wszystkie ścieżki w <math>\overline{G}_f</math> z <math>s</math> do <math>t</math> są najkrótszymi ścieżkami. Jeżeli chcemy wyszukać przepływ blokujący, to zauważmy, że robiąc to w sieci warstwowej, będziemy mieli spełniony automatycznie [[#warunki_blokujace|warunek 1]] definicji przepływu blokującego. W grafie <math>\overline{G}_f</math> wszystkie ścieżki są najkrótsze, jednak nie wszystkie ścieżki muszą prowadzić do <math>t</math>. Jeżeli usuniemy zawczasu z grafu <math>\overline{G}_f</math> krawędzie, które prowadzą donikąd, to ścieżki z <math>s</math> do <math>t</math> będziemy mogli wyszukiwać w czasie <math>O(n)</math>.


{{algorytm|[Dinica] znajduje przepływ blokujący w grafie <math>G_f</math>|algorytm_Dinica|
{{algorytm|[Dinica] znajduje przepływ blokujący w grafie <math>G_f</math>|algorytm_Dinica|
3=
3=
   DINIC-PRZEPŁYW-BLOKUJĄCY(G_f, s, t)
   DINIC-PRZEPŁYW-BLOKUJĄCY<math>(G_f, s, t)</math>
   1  <math>b = 0</math>
   1  <math>b = 0</math>
   2  skonstruuj graf <math>\overline{G}_f</math>
   2  skonstruuj graf <math>\overline{G}_f</math>
   3 '''for''' każdy <math>v \in V</math> '''do'''
   3  '''while''' <math>\overline{E}_f \neq \emptyset</math> '''do'''
  4    <math>out(v) =</math> liczba krawędzi wychodzących z <math>v</math>
   4 '''begin'''
  5 '''while''' <math>\overline{E}_f \neq \emptyset </math> '''do'''
   5   znajdź ścieżkę <math>p</math> z <math>s</math> do <math>t</math> w <math>\overline{G}_f</math>
   6 '''begin'''
   6   '''for''' każda krawędź <math>(u,v) \in p</math> '''do'''
   7   znajdź ścieżkę <math>p</math> z <math>s</math> do <math>t</math> w <math>\overline{G}_f</math>
   7   '''begin'''
   8   '''for''' każda krawędź <math>(u,v) \in p</math> '''do'''
   8      <math>b(u,v) = b(u,v) + c_f(p)</math>
   9   '''begin'''
   9      <math>b(v,u) = -b(u,v)</math>
   10    <math>b(u,v) = b(u,v) + c_f(p)</math>
   10     usuń rekurencyjnie <math>u</math> i inne wierzchołki jeżeli nie wychodzi z nich żadna krawędź residualna
   11    <math>b(v,u) = -b(u,v)</math>
   11 '''end'''
   12     '''if''' <math>b(u,v) = c_f(u,v)</math> '''then'''
   12 '''return''' <math>b</math>
   13    '''begin'''
  14      <math>out(u) = out(u)-1</math>
  15      '''if''' <math>out(u)=0</math> '''then''' <math>\overline{G}_M = \overline{G}_m - u</math>
  16  '''end'''
   17 '''end'''
  18 '''return''' <math>b</math>
}}
}}


Działanie tego algorytmu zobrazowane jest na następującej animacji.
Działanie tego algorytmu zobrazowane jest na następującej animacji.
<flash>file=Zasd_ilustr_p.swf |width=600|height=500</flash>
[[File:Zasd_ilustr_p.svg|800x300px|thumb|center]]
Zauważmy, że po zakończeniu działania algorytmu, w grafie <math>\overline{G}_f</math> nie pozostanie żadna ścieżka z <math>s</math> do <math>t</math>. Skonstruowany przepływ będzie więc przepływem blokującym.


Zauważmy, że w po zakończeniu działania algorytmu w grafie <math>\overline{G}_f</math> nie pozostanie żadna ścieżka z <math>s</math> do <math>t</math>. Skonstruowany przepływ będzie wiec przepływem blokującym.
Główna pętla programu w liniach 5-17 wykonana zostanie co najwyżej <math>m</math> razy, bo w każdym jej przebiegu nasycana jest co najmniej jedna krawędź. Pętlę można zaimplementować tak, aby działała w czasie <math>O(n)</math>, dlatego całkowity czas działania tej procedury wynosi <math>O(nm)</math>. Korzystając z [[#wnisek_4|Wniosku 4]] widzimy, że czas działania algorytmu Dinica wynosi <math>O(mn^2)</math>.
 
Główna pętla programu w liniach 5-17 wykonana zostanie co najwyżej <math>m</math> razy, bo w każdym jej przebiegu nasycona jest co najmniej jedna krawędź. Pętlę można zaimplementować aby działała w czasie <math>O(n)</math>, dlatego całkowity czas działania tej procedury wynosi <math>O(nm)</math>. Korzystając z [[#wnisek_4|Wniosku 4]] widzimy, że czas działania algorytmu Dinica wynosi <math>O(mn^2)</math>.


== Znajdowanie przepływu blokującego - Algorytm trzech Hindusów ==
== Znajdowanie przepływu blokującego - Algorytm trzech Hindusów ==


W algorytmie tym użyjemy pojęcia '''przepustowości wierzchołka''' w sieci <math>G_f</math>, którą definiujemy jako:
W algorytmie tym użyjemy pojęcia '''przepustowości wierzchołka''' w sieci <math>G</math>, którą definiujemy jako:


{{wzor2|1=
{{wzor2|1=
Linia 155: Linia 147:
}}
}}


W algorytmie trzech Hindusów, który nazywany jest też algorytmem MKM, od nazwisk autorów, będziemy w każdym wykonaniu głównej pętli algorytmu nasycać jeden wierzchołek. Przesyłając z niego przepływ do przodu i do w pewnym sensie do tyłu. W czasie wykonywania pętli funkcja <math>f</math> przestanie spełniać warunek zachowania przepływu, jednak pod koniec ten warunek zostanie przywrócony. Użyjemy tutaj dwóch pomocniczych procedur:
W algorytmie trzech Hindusów, który nazywany jest też algorytmem MKM (od nazwisk autorów), będziemy w każdym wykonaniu głównej pętli algorytmu nasycać jeden wierzchołek, przesyłając z niego przepływ do przodu i w pewnym sensie do tyłu. W czasie wykonywania pętli funkcja <math>f</math> przestanie spełniać warunek zachowania przepływu, jednak pod koniec ten warunek zostanie przywrócony. Użyjemy tutaj dwóch pomocniczych procedur:
* procedury PRZEŚLIJ(v) - jeżeli do wierzchołka <math>v</math> wpływa większy przepływ niż wypływa, to procedura ta przesyła ten nadmiar do przodu w grafie <math>\overline{G}_f</math> nasycając po kolei krawędzie wychodzące z <math>v</math>,
* procedury {{kotwica|przeslij|PRZEŚLIJ<math>(v)</math>}} - jeżeli do wierzchołka <math>v</math> wpływa większy przepływ niż wypływa, to procedura ta przesyła ten nadmiar do przodu w grafie <math>\overline{G}_f</math>, nasycając po kolei krawędzie wychodzące z <math>v</math>,
* procedury COFNIJ(v) - jeżeli z wierzchołka <math>v</math> wypływa więcej niż do niego wpływa, to procedura ta kompensuje ten niedomiar przesyłając przepływ z wierzchołków z których istnieją w <math>\overline{G}_f</math> krawędzie do <math>v</math> nasycając po kolei krawędzie wchodzące do <math>v</math>.
* procedury {{kotwica|cofnij|COFNIJ<math>(v)</math>}} - jeżeli z wierzchołka <math>v</math> wypływa więcej niż do niego wpływa, to procedura ta kompensuje ten niedomiar, przesyłając przepływ z wierzchołków, z których istnieją w <math>\overline{G}_f</math> krawędzie do <math>v</math>, nasycając po kolei krawędzie wchodzące do <math>v</math>.


{{algorytm|[Malhotra, Kumar i Maheshwari] znajduje przepływ blokujący w grafie <math>G_f</math>|algorytm_Dinica|
{{algorytm|[Malhotra, Kumar i Maheshwari] znajduje przepływ blokujący w grafie <math>G_f</math>|algorytm_Dinica|
3=
3=
   MKM-PRZEPŁYW-BLOKUJĄCY(G_f, s, t)
   MKM-PRZEPŁYW-BLOKUJĄCY<math>(G_f, s, t)</math>
   1  <math>b = 0</math>
   1  <math>b = 0</math>
   2  skonstruuj graf <math>\overline{G}_f</math>
   2  skonstruuj graf <math>\overline{G}_f</math>
   3  '''while''' <math>\overline{E}_f \neq \emptyset </math> '''do'''
   3  '''while''' <math>\overline{E}_f \neq \emptyset</math> '''do'''
   4  '''begin'''
   4  '''begin'''
   5    znajdź wierzchołek o najmniejszym <math>c(v)</math>
   5    znajdź wierzchołek o najmniejszym <math>c(v)</math>
   6    prześlij <math>c(v)</math> jednostek przepływu krawędziami wychodzącymi z <math>v</math>
   6    prześlij <math>c(v)</math> jednostek przepływu krawędziami wychodzącymi z <math>v</math>
   7    prześlij <math>c(v)</math> jednostek przepływu krawędziami wchodzącymi do <math>v</math>
   7    prześlij <math>c(v)</math> jednostek przepływu krawędziami wchodzącymi do <math>v</math>
   8    '''for''' każdy <math>w \in V</math> '''do'''
   8    '''for''' <math>i=d(s,v)+1</math> '''to''' <math>n-1</math> '''do'''
   9   '''begin'''
   9     '''foreach''' <math>w \in \{w \in V: d(s,w) = i\}</math> '''do'''  
   10     PRZEŚLIJ(w)
   10       [[#przeslij|PRZEŚLIJ]]<math>(w)</math>
   11     COFNIJ(w)
   11   '''for''' <math>i=d(s,v)-1</math> '''downto''' <math>1</math> '''do'''
   12   '''end'''
   12     '''foreach''' <math>w \in \{w \in V: d(s,w) = i\}</math> '''do'''  
   13  usuń <math>v</math> z grafu poprawiając przepustowości wierzchołków sąsiednich
   13       [[#cofnij|COFNIJ]]<math>(w)</math>
   13 '''end'''
  14   usuń <math>v</math> z grafu poprawiając przepustowości wierzchołków sąsiednich
   15 '''return''' <math>b</math>
   15 '''end'''
   16 '''return''' <math>b</math>
}}
}}


Działanie tego algorytmu zobrazowane jest na następującej animacji.
Działanie tego algorytmu zobrazowane jest na następującej animacji.
<flash>file=Zasd_Ilustr_q.swf |width=600|height=500</flash>
[[File:Zasd_ilustr_q.svg|800x300px|thumb|center]]
 


Zauważmy, że ponieważ wybraliśmy wierzchołek o najmniejszej przepustowości, to zawsze w procedurach PRZEŚLIJ i COFNIJ uda nam sie przesłać nadmiar i bądź zrekompensować niedomiar w wierzchołku.
Zauważmy, że ponieważ wybraliśmy wierzchołek o najmniejszej przepustowości, to zawsze w procedurach [[#przeslij|PRZEŚLIJ]] i [[#cofnij|COFNIJ]] uda nam się przesłać nadmiar bądź zrekompensować niedomiar w wierzchołku.


Zauważmy, że główna pętla procedury może wykonać się co najwyżej <math>n-2</math> razy, ponieważ za każdym razem nasycany jest co najmniej jeden wierzchołek grafu. Policzmy teraz ile razy łącznie będą nasycane krawędzie w trakcie wykonywania procedur PRZEŚLIJ i COFNIJ. Co najwyżej <math>m</math> razy będziemy przesyłać przepływ nasycając krawędzie. Natomiast liczba przesłań nie nasycających krawędzi nie przekroczy <math>O(n^2)</math>, gdyż dla każdego wierzchołka w wykonaniu procedury PRZEŚLIJ i COFNIJ wykonujemy co najwyżej jedno przesłania nie nasycające, a operacji tych łącznie wykonywanych jest <math>O(n^2)</math>. Czas potrzebny na znalezienie przepływu blokującego wynosi więc <math>O(n^2)</math>, łącząc ten algorytm z [[#algorytm_Dinica|algorytmem Dinica]] otrzymujemy algorytm znajdujący maksymalny przepływ w grafie w czasie <math>O(n^3)</math>.
Zauważmy, że główna pętla procedury może wykonać się co najwyżej <math>n-2</math> razy, ponieważ za każdym razem nasycany jest co najmniej jeden wierzchołek grafu. Policzmy teraz, ile razy łącznie będą nasycane krawędzie w trakcie wykonywania procedur [[#przeslij|PRZEŚLIJ]] i [[#cofnij|COFNIJ]]. Co najwyżej <math>m</math> razy będziemy przesyłać przepływ nasycając krawędzie. Natomiast liczba przesłań nie nasycających krawędzi nie przekroczy <math>O(n^2)</math>, gdyż dla każdego wierzchołka w wykonaniu procedury [[#przeslij|PRZEŚLIJ]] i [[#cofnij|COFNIJ]] wykonujemy co najwyżej jedno przesłanie nie nasycające, a operacji tych łącznie wykonywanych jest <math>O(n^2)</math>. Czas potrzebny na znalezienie przepływu blokującego wynosi więc <math>O(n^2)</math>. Łącząc ten algorytm z [[#algorytm_Dinica|algorytmem Dinica]], otrzymujemy algorytm znajdujący maksymalny przepływ w grafie w czasie <math>O(n^3)</math>.

Aktualna wersja na dzień 11:28, 5 wrz 2023

Abstrakt

W wykładzie tym przedstawimy trzy algorytmy znajdowania przepływu w grafie. Pierwszym będzie algorytm Edmondsa-Karpa działający w czasie O(nm2). Następnym będzie algorytm Dinica działający w czasie O(n2m), oraz trzecim tak zwany algorytm trzech Hindusów, działający w czasie O(n3). Nazwiska tych tytułowych Hindusów to Malhotra, Kumar i Maheshwari. Dwa ostatnie algorytmy oparte będą na konstrukcji przepływów blokujących, które są analogiczną konstrukcją do konstrukcji maksymalnego zbioru rozłącznych ścieżek, której użyliśmy w algorytmie Hopcrofta-Karpa.

Algorytm Edmonds’a-Karp’a

Algorytm Edmonds'a-Karp'a to algorytm Forda-Fulkersona w, którym zamiast dowolnej ścieżki powiększającej wybieramy zawsze najkrótszą ścieżkę powiększającą. Zakładamy tutaj, że wszystkie krawędzie mają jednostkowe długości. Taka modyfikacja pozwala poprawić ograniczenie w czasie działania tego algorytmu. Udowodnimy, że algorytm Edmonds’a–Karp’a działa w czasie O(nm2). W naszej analizie będziemy korzystać z zapisu df(u,v) dla odległości z u do v w Gf, przy założenie, że każda krawędź ma jednostkową wagę.

Lemat 1

Jeśli algorytm Edmondsa–Karpa działa w sieci przepływowej G=(V,E) ze źródłem s i ujściem t, to wtedy dla wszystkich wierzchołków vV{s,t}, odległość df(s,v) w sieci rezydualnej Gf nie maleje.

Dowód

Przypuśćmy, że dla pewnego wierzchołka vV{s,t} istnieje powiększający przepływ, który powoduje zmniejszenie odległości najkrótszej ścieżki z s do v, a następnie otrzymamy wynik sprzeczny z tym założeniem. Niech f będzie przepływem zaraz przed pierwszym powiększeniem, które skraca długość najkrótszej ścieżki i niech f będzie przepływem następującym zaraz potem. Niech v będzie wierzchołkiem o minimalnym df(s,v), którego dystans został zmniejszony poprzez to powiększenie tak, że df(s,v)<df(s,v). Niech p=suv będzie najkrótszą ścieżką z s do v w Gf, tak że (u,v)Ef oraz:
df(s,u)=df(s,v)1

Ze względu na sposób wybrania v, wiemy że odległość z wierzchołka u się nie zmniejszyła, to znaczy:

df(s,u)df(s,u)

Twierdzimy, że (u,v)Ef. Dlaczego? Gdybyśmy mieli (u,v)Ef, wówczas z nierówności trójkąta dla s,v i u oraz powyższych nierówności wynikałoby:

df(s,v)df(s,u)+1df(s,u)+1df(s,v)

Co jest sprzeczne z założeniem, że df(s,v)<df(s,v). Jak możemy zatem otrzymać (u,v)Ef i (u,v)Ef? Powiększeniu przepływu z f do f powinno także powiększyć przepływ z v do u. Algorytm Edmondsa–Karpa zawsze powiększa przepływ wzdłuż najkrótszych ścieżek i dlatego też najkrótsza ścieżka z s do u w Gf posiada (v,u) jako ostatnią krawędź. Dlatego mamy:

df(s,v)=df(s,u)1=df(s,u)2=df(s,v)2
co jest sprzeczne z założeniem, że df(s,v)<df(s,v). Wnioskujemy zatem, że założenie, iż taki wierzchołek v istnieje, jest nieprawdziwe.

Następujące twierdzenie ogranicza liczbę iteracji algorytmu Edmondsa–Karpa.

Twierdzenie 2

Jeśli algorytm Edmondsa–Karpa działa w sieci przepływowej G=(V,E) ze źródłem s i ujściem t, wówczas całkowita liczba przepływów powiększających znalezionych w algorytmie wynosi O(VE).

Dowód

Mówimy, że krawędź (u,v) w sieci rezydualnej Gf jest krytyczna na ścieżce powiększającej p, jeśli przepustowość rezydualna p jest przepustowością rezydualną (u,v), to znaczy jeśli cf(p)=cf(u,v). Po tym, jak otrzymamy powiększający przepływ wzdłuż ścieżki powiększającej, każda krawędź krytyczna na ścieżce znika z sieci rezydualnej. Ponadto co najmniej jedna krawędź na dowolnej ścieżce musi być krytyczna. Pokażemy, że każda z |E|krawędzi może stać się krytyczna co najwyżej |V|/21 razy.

Niech u i v będą wierzchołkami w V połączonymi krawędzią E. Ponieważ ścieżki powiększające są najkrótszymi ścieżkami, to dla kawędzi krytycznej (u,v), otrzymujemy

df(s,v)=df(s,u)+1

Gdy tylko przepływ jest zwiększony, krawędź (u,v) znika z sieci rezydualnej. Nie może ona się znów pojawić na żadnej innej ścieżce powiększającej dopóki przepływ z u do v nie będzie zmniejszony, a nastąpi to tylko wtedy, kiedy (v,u) pojawi się na ścieżce powiększającej. Jeśli f jest przepływem w G i to zdarzenie ma miejsce, wówczas mamy:

df(s,u)=df(s,v)+1

Ponieważ df(s,v)df(s,v), co wynika z lematu 1, otrzymujemy

df(s,u)=df(s,v)+1df(s,v)+1=df(s,u)+2
Czyli od czasu, kiedy (u,v) stało sie krytyczne, do czasu kiedy ponownie stanie się krytyczne, dystans ze źródła do u zwiększa się o co najmniej 2. Dystans do u wynosi początkowo co najmniej 0. Wierzchołki pośrednie na najkrótszej ścieżce z s do u nie mogą zawierać s, u ani t (ponieważ to, że (u,v) jest krytyczna oznacza, że ut). Dlatego też odległość do u może wynosić co najwyżej |V|2. Stąd (u,v) może stać sie krytyczne co najwyżej (|V|2)/2=|V|/21 razy. Ponieważ istnieje O(|E|) par wierzchołków pomiędzy którymi może istnieć krawędź w grafie rezydualnym, to całkowita liczba krawędzi krytycznych podczas działania algorytmu Edmondsa–Karpa wynosi O(|V||E|), bo każda ścieżka powiększająca ma co najmniej jedną krawędź krytyczną.

Ponieważ każdą iterację algorytmu FORD-FULKERSON można zaimplementować w czasie O(|E|), to całkowity czas działania algorytmu Edmondsa-Karpa wynosi O(|V||E|2). W następnych częściach wykładu pokażemy, jak wykorzystując przepływy blokujące poprawić ten wynik do czasu O(|V|3).

Przepływ blokujący

Przepływem blokującym w sieci rezydualnej Gf nazywamy taki przepływ b w Gf, że:{{{2}}}

  1. każda ścieżka z s do t w b jest najkrótszą ścieżką w Gf,
  2. oraz każda najkrótsza ścieżka w Gf zawiera krawędź nasyconą w Gf+b.

Zauważ, że jest to definicja, która odpowiada pojęciu maksymalnego zbioru najkrótszych ścieżek powiększających użytemu w Wykładzie 7. Załóżmy na chwilę, że mamy algorytm znajdujący przepływ blokujący. Pokażemy jak go wykorzystać do znalezienia przepływu maksymalnego, jest to algorytm Dinica. Algorytmy na znajdowanie przepływu blokującego pokażemy w dalszej części tego wykładu.

Algorytm [Dinica] znajduje przepływ maksymalny w grafie G


 DINIC(G,s,t)
 1  f=0
 2  while istnieje ścieżka od s do t w Gf do
 3  begin
 4    znajdź przepływ blokujący b w Gf
 5    f=f+b
 6  end
 7  return f

Poprawność algorytmu Dinica wynika bezpośrednio z twierdzenia o maksymalnym przepływie i minimalnym przekroju, gdyż po zakończeniu algorytmu nie ma już w sieci G ścieżek powiększających. Zastanówmy się teraz, ile razy może zostać wykonana pętla while, czyli innymi słowy ile razy będzie konieczne znalezienie przepływu blokującego.

Lemat 3

Niech b będzie przepływem blokującym w Gf, wtedy długość najkrótszej ścieżki powiększającej w Gf+b jest większa niż długość najkrótszej ścieżki powiększającej w Gf.

Dowód

Załóżmy, że długość najkrótszej ścieżki p w Gf+b jest nie większa niż długość najkrótszej ścieżki w Gf. Wtedy ścieżka p ma z przepływem blokującym b wspólną krawędź nasyconą. Niech uv będzie ostatnią taką krawędzią na p. Oznacza to, że krawędź vu musiała należeć do przepływu b. Inaczej w Gf+b krawędź uv nadal byłaby nasycona. Ponieważ b może zostać rozłożone na sumę pewnych najkrótszych ścieżek w Gf, to z lematu 1, wiemy, że odległość z s do u nie zmalała, tzn. df(s,u)df+b(s,u). Jednak ponieważ p jest najkrótszą ścieżką z s do t, oznacza to, że odległość do v wzrosła o co najmniej 2, df(s,v)+2df+b(s,v). Kawałek ścieżki p od v do t też jest najkrótszą ścieżką, więc df(s,t)+2df+b(s,t). Długość najkrótszej ścieżki w grafie rezydualnym musiała więc wzrosnąć.

Wniosek 4

Ponieważ maksymalna długość najkrótszej ścieżki może wynosić co najwyżej n1, maksymalna liczba faz w algorytmie Dinica wynosi n.

Znajdowanie przepływu blokującego - Algorytm Dinica

Zanim przejdziemy do opisu algorytmów znajdujących przepływ blokujący, wprowadźmy pojęcie sieci warstwowej. Sieć warstwową Gf dla sieci rezydualnej Gf=(V,Ef) definiujemy jako graf skierowany Gf=(V,Ef) o następującym zbiorze krawędzi:

Ef={(u,v):(u,v)Ef i df(s,u)+1=df(s,v)}.

Zauważmy, że wszystkie ścieżki w Gf z s do t są najkrótszymi ścieżkami. Jeżeli chcemy wyszukać przepływ blokujący, to zauważmy, że robiąc to w sieci warstwowej, będziemy mieli spełniony automatycznie warunek 1 definicji przepływu blokującego. W grafie Gf wszystkie ścieżki są najkrótsze, jednak nie wszystkie ścieżki muszą prowadzić do t. Jeżeli usuniemy zawczasu z grafu Gf krawędzie, które prowadzą donikąd, to ścieżki z s do t będziemy mogli wyszukiwać w czasie O(n).

Algorytm [Dinica] znajduje przepływ blokujący w grafie Gf


 DINIC-PRZEPŁYW-BLOKUJĄCY(Gf,s,t)
 1  b=0
 2  skonstruuj graf Gf
 3  while Ef do
 4  begin
 5    znajdź ścieżkę p z s do t w Gf
 6    for każda krawędź (u,v)p do
 7    begin
 8      b(u,v)=b(u,v)+cf(p)
 9      b(v,u)=b(u,v)
 10     usuń rekurencyjnie u i inne wierzchołki jeżeli nie wychodzi z nich żadna krawędź residualna 
 11 end
 12 return b

Działanie tego algorytmu zobrazowane jest na następującej animacji.

Plik:Zasd ilustr p.svg

Zauważmy, że po zakończeniu działania algorytmu, w grafie Gf nie pozostanie żadna ścieżka z s do t. Skonstruowany przepływ będzie więc przepływem blokującym.

Główna pętla programu w liniach 5-17 wykonana zostanie co najwyżej m razy, bo w każdym jej przebiegu nasycana jest co najmniej jedna krawędź. Pętlę tę można zaimplementować tak, aby działała w czasie O(n), dlatego całkowity czas działania tej procedury wynosi O(nm). Korzystając z Wniosku 4 widzimy, że czas działania algorytmu Dinica wynosi O(mn2).

Znajdowanie przepływu blokującego - Algorytm trzech Hindusów

W algorytmie tym użyjemy pojęcia przepustowości wierzchołka w sieci G, którą definiujemy jako:

c(v)=min{uVc(u,v),uVc(v,u)}.

W algorytmie trzech Hindusów, który nazywany jest też algorytmem MKM (od nazwisk autorów), będziemy w każdym wykonaniu głównej pętli algorytmu nasycać jeden wierzchołek, przesyłając z niego przepływ do przodu i w pewnym sensie do tyłu. W czasie wykonywania pętli funkcja f przestanie spełniać warunek zachowania przepływu, jednak pod koniec ten warunek zostanie przywrócony. Użyjemy tutaj dwóch pomocniczych procedur:

  • procedury PRZEŚLIJ(v) - jeżeli do wierzchołka v wpływa większy przepływ niż wypływa, to procedura ta przesyła ten nadmiar do przodu w grafie Gf, nasycając po kolei krawędzie wychodzące z v,
  • procedury COFNIJ(v) - jeżeli z wierzchołka v wypływa więcej niż do niego wpływa, to procedura ta kompensuje ten niedomiar, przesyłając przepływ z wierzchołków, z których istnieją w Gf krawędzie do v, nasycając po kolei krawędzie wchodzące do v.

Algorytm [Malhotra, Kumar i Maheshwari] znajduje przepływ blokujący w grafie Gf


 MKM-PRZEPŁYW-BLOKUJĄCY(Gf,s,t)
 1  b=0
 2  skonstruuj graf Gf
 3  while Ef do
 4  begin
 5    znajdź wierzchołek o najmniejszym c(v)
 6    prześlij c(v) jednostek przepływu krawędziami wychodzącymi z v
 7    prześlij c(v) jednostek przepływu krawędziami wchodzącymi do v
 8    for i=d(s,v)+1 to n1 do
 9      foreach w{wV:d(s,w)=i} do 
 10       PRZEŚLIJ(w)
 11   for i=d(s,v)1 downto 1 do
 12     foreach w{wV:d(s,w)=i} do 
 13       COFNIJ(w)
 14   usuń v z grafu poprawiając przepustowości wierzchołków sąsiednich
 15 end
 16 return b

Działanie tego algorytmu zobrazowane jest na następującej animacji.

Plik:Zasd ilustr q.svg

Zauważmy, że ponieważ wybraliśmy wierzchołek o najmniejszej przepustowości, to zawsze w procedurach PRZEŚLIJ i COFNIJ uda nam się przesłać nadmiar bądź zrekompensować niedomiar w wierzchołku.

Zauważmy, że główna pętla procedury może wykonać się co najwyżej n2 razy, ponieważ za każdym razem nasycany jest co najmniej jeden wierzchołek grafu. Policzmy teraz, ile razy łącznie będą nasycane krawędzie w trakcie wykonywania procedur PRZEŚLIJ i COFNIJ. Co najwyżej m razy będziemy przesyłać przepływ nasycając krawędzie. Natomiast liczba przesłań nie nasycających krawędzi nie przekroczy O(n2), gdyż dla każdego wierzchołka w wykonaniu procedury PRZEŚLIJ i COFNIJ wykonujemy co najwyżej jedno przesłanie nie nasycające, a operacji tych łącznie wykonywanych jest O(n2). Czas potrzebny na znalezienie przepływu blokującego wynosi więc O(n2). Łącząc ten algorytm z algorytmem Dinica, otrzymujemy algorytm znajdujący maksymalny przepływ w grafie w czasie O(n3).