Budowanie sieci rezydualnej w przepływach:
Dla każdej krawędzi uv, danego przepłwu f oraz (G,c,s,t) zachodzi w sieci rezydualnej:
c_f(uw) = c(uw) - f(uw) jeśli uw < E(G) i wu !< E(G)c_f(uw) = f(wu) jeśli uw !< E(G) i wu < E(G)c_f(uw) = (c(uw) - f(uw)) + f(wu) gdy wu i uw <E(G)
W tak zdefiniowanej sieci rezydualnej ścieżka powiększająca to każda ścieżka od s do t.
Do momentu aż istnieje ścieżka powiększająca w sieci rezydualnej dla danego f, to f nie jest maksymalne (cały czas można powiększyć f wzdłuż tej ścieżki, otrzymując większy przepływ).
Ford Fulkerson
function FordFulkerson((G,c,s,t)){
f <- zerowy przepływ dla G
(R,r) <- sieć rezydualna na G dla f
while(istnieje ścieżka powiększająca P w R){
r = min(v_i, v_i+1) w P
powiększ f o a na wszystkich krawędziach P;
Uaktualnij R o r na wszystkich krawędziach P;
}
return f;
}Poprawność algorytmu wynika bezpośrednio z twierdzenia Forda Fulkersona.
Twierdzenie Forda Fulkersona
Przepływ f jest maksymalny wtw. gdy nie istnieją dla niego żadne ścieżki powiększające w sieci rezydulanej.
Dowód przez sprzeczność. Powiedzmy że f to przepływ maksymalny, ale ma ścieżkę powiększającą P = {v_1, …, v_n} . To oznacza, że istnieje ścieżka od s do t w sieci rezydualnej dla f. Zdefiniujmy f’ jako:
- f(uw) gdy uw !< P
- f(uw) + r(P) gdy uw < P
Jako że powiększamy każdą krawędź ścieżki od v_1 - v_2 do v_n-1 -v_n, to zwiększyliśmy wartość przepływu (v_1 = s, więc wypływa więcej w f’ niż w f), oraz zachowane zostało prawo Kirchoffa (dla każdego v_i v_i+1 tyle o ile zwiększyliśmy przepływ, tyle wypłynie v_i+1 v_i+2), więc f’ jest poprawnym przepływem o większej wartości niż f, sprzeczność.
Wadą algorytmu jest zależność złożoności czasowej od wartości maksymalnego przepływu.
Edmond Karps
Zmodyfikowany Bellman Ford - zamiast szukać jakiejkolwiek ścieżki powiększającej, szukamy najkrótszej ścieżki powiększającej
function EdmondKarps((G,c,s,t)){
f <- zerowy przepływ
(R,r) <- sieć rezydualna dla f
while istnieje ścieżka P od s do t w R{
P = {v1,....,vn}; // najkrótsza ścieżka
a <- min( r(vi-vi+1));
Powiększ f o a na wszystkich krawędziach P;
Uaktualnij (R,r) o a na wszystkich krawędziach P;
}
return f
}Dowód:
-
d_f(uv)- odległość między u i v w sieci rezydualnej dla f -
L_f- liczba krawędzi, które należą do jakiejkolwiek najkrótszej ścieżki od s do t w sieci rezydualnej dla f -
f i f’ - stan przed i po wykonaniu pętli while
Wybierzmy jakąś najkrótszą ścieżkę od s do t. Wykonanie pętli while może usunąć krawędzie z wierzchołków bliższych do s do wierzchołków dalszych do s oraz dodać krawędzie z wierzchołków dalszych od s do wierzchołków bliższych do s. Nie ma więc możliwości znalezienia krótszej ścieżki po wykonaniu pętli. -
a) Dla każdego v zachodzi
d_f'(s,v) >= d_f(s,v). Załóżmy przeciwnie. -
Istnieje takie v, gdzie
d_f'(s,v) < d_f(s,v). Wybieramy takie v, które jest najbliższe do s, czyli ma najmniejszed_f'(s,v). Niech P’ to ścieżka w sieci rezydualnej dla f’ od s do v. -
w to ostatni wierzchołek przed v w P’. Dla niego
d_f'(s,w) = d_f'(s,v) - 1 -
Jako że w jest bliżej do s niż v (a v jest najbliższym wierzchołkiem zaprzeczającym tezie), to
-
d_f'(s,w) >= d_f(s,w)Teraz istnieją dwa przypadki:- albo w->v istniało w sieci rezydualnej dla f, wtedy
d_f(s,v) <= d_f(s,w) + 1 <= d_f'(s,w) + 1 = d_f'(s,v)bo w poprzedza v w P’ - albo w->v nie istniało w sieci rezydualnej f. Nowe krawędzie powstają tylko wstecz wobec znalezionego P w while, więc v->w musiało leżeć na najkrótszej ścieżce od s do t, więc:
d_f(s,w) = d_f(s,v) + 1, =>d_f(s,v) = d_f(s,w) - 1 <= d_f'(s,w)j - 1 = d_f'(s,v) - 2 < d_f'(s,v)
- albo w->v istniało w sieci rezydualnej dla f, wtedy
-
teraz pokażemy że jeśli
d_f'(s,t) = d_f(s,t) to L_f' < L_f. -
Rozważmy najkrótszą ścieżkę P’ od s do t w sieci rezydualnej f’.
-
P’= {w_1, …, w_k}; Rozważmy ich odległości od s w sieci rezydualnej dla f.
-
Może zachodzić:
d_f(w_i+1) <= d_f(w_i) + 1jeśli krawędź w_i w_i+1 istniała w SR dla fd_f(w_i+1) <= d_f(w_i) - 1jeśli krawędź w_i w_i+1 powstała w trakcie iteracji- Jako że
d_f(s,t) = d_f'(s,t)to nie może w P’ wchodzić żadna krawędź typu drugiego, bo wtedy długość byłaby inna - Zatem zbiór L_f’ < L_f
-
Jako że w trakcie iteracji L_f’ straciło jedną krawędź, to L_f’ < L_f (ilościowo)
-
W takim wypadku skoro d(s,t) nie maleje, a może przyjąć co najwyżej n wartości, a jako że dla jednej wartości d(s,t) pętla może wykonać się m razy(ponieważ każda ścieżka może składać się z co najwyżej m krawędzi, a liczba krawędzi maleje z każdą iteracją) to ogranicza się to w O(nm), BFS w każdej iteracji kosztuje O(m). Więc dla każdej wartości d (n) wykonujemy co najwyżej m pętli while, w której wywołujemy BFS, sumarycznie O(nm
Sieci rezydualne z kosztami
Dla (G,c,s,t) oraz funkcji kosztów k i przepływu f nazywamy graf skierowany R z funkcją wag c_f oraz funkcją kosztów k_f:
- c_f(uw) = c(uw) - f(uw) i k_f(uw) = k(uw) gdy uw < E(G) i wu <! E(G)
- c_f(uw) = f(wu) i k_f(uw) = -k(wu) gdy uw <! E(G) oraz wu < E(G)
Twierdzenie o minimalnym koszcie
Niech f będzie maksymalnym przepływem z funkcją kosztu k. Wówczas f jest maksymalnym przepływem o minimalnym koszcie wtw. gdy odpowiadająca mu sieć rezydualna nie ma cyklu o ujemnym koszcie.
=> ) Powiększenie przepływu wzdłuż ujemnego cyklu zmniejszy koszt.
Jeżeli powiększymy przepływ wzdłuż ujemnego cyklu to zmniejszymy koszt. Przepływ pozostaje o tej samej wartości, ale koszt się zmniejsza.
<= ) Niech f to przepływ maksymalny nie minimalizujący kosztów. Niech f’ minimalizuje koszt o tym samym przepływie co f. f’ minimalizuje ilość różniących się z f krawędzi. Niech S to zbiór krawędzi gdzie {uw: f(uw) < f’(uw) albo f(wu) > f’(wu)} (albo mniej przesyłam albo mniej zwracam, czyli albo wysyłam za mało albo cofam za dużo). S’ = {wu : }
Z prawa kirchoffa co daje .
Jeśli do v wchodzi jakaś krawędź z S, to pierwsza strona równania jest większa niż 0, więc musi też wychodzić z niego krawędź z S. W S musi być cykl, ponieważ jest niepuste ponieważ f’ i f się różnią oraz spełniony jest powyższy warunek. Oznaczmy go jako C. Przez C’ oznaczamy odwrócenie tego cyklu, który musi leżeć w S’ z definicji.
- C to cykl dodatni. Jeżeli uv jest dodatnia, to w C’ będzie ujemna. Suma kosztów w C’ będzie wtedy ujemna. Wtedy znaleźliśmy cykl ujemny w sieci rezydualnej f’, co jest sprzeczne
- C to cykl zerowy. C’ też zerowy. Wtedy można wziąć przepływ f”, tak że można zwiększyć wartość przepływu na f’ o tyle ile maksymalnie się da. Skoro f” zmienia się na cyklu, to ma ten sam koszt. Nasyciliśmy w ten sposób jakąś krawędź z C, co oznacza że nie należy ona do sieci rezydualnej f”, co oznacza że ta nasycona krawędź nie znajdzie się w zrekonstruowanym zbiorze S i S”. Na tej krawędzi f i f” się nie różnią, co jest sprzeczne z minimalnością różniących się krawędzi f i f’, sprzeczność.
function cycleCancelling(G,c,s,t){
f<- maksymalny przeplyw dla (G,c,s,t);
(R,r) <- siec rezydualna dla f;
while istnieje ujemny cykl C w R,k:
a <- min r(v_i v_i+1) dla kazdego v_i nalezacego do C
zwiekszamy kazda krawedz w C o a;
aktualizujemy kazda krawedz z C w R o a;
zwroc f
}Do dokończenia

ZAD 1

ZAD 2
a) Ford fulkerson ma złożoność O(mF_max); k-krotny podpodział wydłuży działanie algorytmu k+1 krotnie, ponieważ z każdej krawędzi robi się k+1 krawędzi, F_max pozostaje takie same, T => (k+1) T
b) Pomimo tego że każda przepustowość jest k razy większa, to jedna iteracja pętli while złapie teraz k razy większą wartość. Powiększenie przepustowości każdej krawędzi nie wpłynie na czas działania algorytmu forda fulkersona.
ZAD 3
function FindPaths(G, v, w){
(G,c,s,t) <- tupla uzyskana po grafie G, w kazda waga krawedzi 1, s = v, t = w, każdy wierzchołek rozdzielamy na v_in oraz v_out z c = 1, każda inna krawędź ma cap = inf.
f <- zerowy przeplyw
(R,r) <- siec rezydualna dla f
while istnieje sciezka powiekszajaca P od s do t w R{
P = {v_1, ..., v_n};
a = min_{P}r(v_i, v_i+1);
powieksz f o a dla każdej krawędzi w P;
zaktualizuj R o a dla każdej krawędzi w R;
}
zwroc f;
}Dlaczego to zadziała: To jest twierdzenie mengera ale na przepływach. Wg. twierdzenia mengera ilość tych ścieżek <=> ilość wierzchołków potrzebnych do rozłączenia v od w. Ilość tych rozłącznych ścieżek to dla sieci przepływowej będzie tak naprawdę mincap, co jest równe maxflow. Poprawność algorytmu wynika z twierdzenia forda fulkersona.
ZAD 4
Do znalezienia jest mincut, min_cut = max_flow z MD2.
function FF((G,c,s,t)){
f<- zerowy przeplyw
(R,r)<- siec rezydualna dla f
while istnieje P powiekszajaca z s do t w R:
a = min(v_i , v_i+1) z P;
powieksz f o a na każdej krawędzi z P
zmień R o a na każdej krawędzi z P
int visited = new int[n];
BFS(s);
S = visited == true;
T = visited == false;
return {(a,b) < E(G) : a < S, b <- T};
}
function BFS(s){
q = new queue<int>();
visited[s] = true;
q.add(s);
while(q.count> 0){
var w = q.pop();
foreach(var u in N_R(w)){ // tutaj po R operuje
if(!visited[u])
visited[u] = true;
q.add(u);
}
}
}
ZAD 5
a) znajdź przepływ blokujący
function constructLevel(G, s, t){
dist = new int[n];
visited = new bool[n];
q = new queue<int>();
dist[s] = 0;
visited[s] = true;
q.push(s);
while(q.count > 0){
var w = q.pop();
foreach(var u in N(w)){
if(!visited[u] && !dead[u]){
visited[u] = true;
dist[u] = dist[w] + 1;
}
}
}
}
function FindBlockingFlow(G,c,s,t){
dead = new bool[n];
constructLevel(G,c,s,t);
d = dist[t];
}