Zaawansowane algorytmy i struktury danych/Wykład 7: 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 18 wersji utworzonych przez 3 użytkowników)
Linia 1: Linia 1:
== Abstrakt ==
== Abstrakt ==


W wykładzie tym skoncentrujemy się na problemie znajdowania najliczniejszych skojarzeń w grafach dwudzielnych. Zaczniemy od przedstawienia idei ścieżek powiększających, a następie użyjemy jej do konstrukcji algorytmu znajdującego maksymalne skojarzenie w grafie <math>G=(V,E)</math> w czasie <math>O(|V||E|)</math>. Następnie przedstawimy algorytm Hopcrofta-Karpa, który działać będzie w czasie czasie <math>O(\sqrt{|V|}|E|)</math>.
W wykładzie tym skoncentrujemy się na problemie znajdowania najliczniejszych skojarzeń w grafach dwudzielnych. Zaczniemy od przedstawienia idei ścieżek powiększających, a następie użyjemy jej do konstrukcji algorytmu znajdującego maksymalne skojarzenie w grafie <math>G=(V,E)</math> w czasie <math>O(|V||E|)</math>. Następnie przedstawimy algorytm Hopcrofta-Karpa, który działać będzie w czasie <math>O(\sqrt{|V|}|E|)</math>.


== Problem maksymalnego skojarzenia w grafie dwudzielnym ==
== Problem maksymalnego skojarzenia w grafie dwudzielnym ==


Niech <math>G=(V,E)</math> będzie grafem nieskierowanym. {{kotwica|skojarzenie|'''Skojarzeniem'''}} w grafie <math>G</math> nazywamy każdy podzbiór krawędzi <math>M\subseteq E</math> taki, w którym co najwyżej jedna krawędź z <math>M</math> jest incydentna z każdym wierzchołkiem w <math>V</math>. O wierzchołku <math>v</math> incydentnym do pewniej krawędzi z <math>M</math> mówimy, że jest '''skojarzony''', w przeciwnym przypadku <math>v</math> nazywamy '''wolnym'''. Podobnie jeżeli krawędź <math>e</math> należy do skojarzenia to mówimy, że jest ona '''skojarzona''' a w przeciwnym wypadku mówimy, że jest to krawędź '''wolna'''. Skojarzenie <math>M</math> nazywamy {{kotwica|maksymalne_skojarzenie|'''maksymalnym'''}} gdy ma ono największą liczność spośród skojarzeń w <math>G</math>. W trakcie tego wykładu zajmiemy się tylko problemem znajdowania skojarzeń w {{kotwica|graf_dwudzielny|'''grafach dwudzielnych'''}} czyli takich w których zbiór wierzchołków można podzielić na <math>V = V_1\cup V_2</math> gdzie <math>V_1</math> i <math>V_2</math> są rozłączne, a wszystkie krawędzie z <math>E</math> prowadzą pomiędzy <math>L</math> i <math>R</math>.
Niech <math>G=(V,E)</math> będzie grafem nieskierowanym. {{kotwica|skojarzenie|'''Skojarzeniem'''}} w grafie <math>G</math> nazywamy każdy podzbiór krawędzi <math>M\subseteq E</math> taki, w którym co najwyżej jedna krawędź z <math>M</math> jest incydentna z każdym wierzchołkiem w <math>V</math>. O wierzchołku <math>v</math> incydentnym do pewniej krawędzi z <math>M</math> mówimy, że jest '''skojarzony''', w przeciwnym przypadku <math>v</math> nazywamy '''wolnym'''. Podobnie jeżeli krawędź <math>e</math> należy do skojarzenia, mówimy, że jest ona '''skojarzona''' a w przeciwnym wypadku mówimy, że jest to krawędź '''wolna'''. Skojarzenie <math>M</math> nazywamy {{kotwica|maksymalne_skojarzenie|'''maksymalnym'''}} gdy ma ono największą liczność spośród skojarzeń w <math>G</math>. W trakcie tego wykładu zajmiemy się tylko problemem znajdowania skojarzeń w {{kotwica|graf_dwudzielny|'''grafach dwudzielnych'''}}, czyli takich, w których zbiór wierzchołków można podzielić na <math>V = V_1\cup V_2</math>, gdzie <math>V_1</math> i <math>V_2</math> są rozłączne, a wszystkie krawędzie z <math>E</math> prowadzą pomiędzy <math>V_1</math> i <math>V_2</math>.


== Ścieżki powiększające ==
== Ścieżki powiększające ==


{{kotwica|ścieżka_powiększająca|'''Ścieżką powiększającą'''}} nazwiemy ścieżkę prostą <math>p</math> taką, że jej krawędzie są na przemian skojarzone i wolne, a końce są wolne. Łatwo zauważyć, że jeżeli istnieje ścieżka powiększająca <math>p</math> względem <math>M</math> to <math>M</math> nie jest skojarzeniem maksymalnym. Używając wtedy ścieżki <math>p</math> możemy skonstruować skojarzenie większe biorąc <math>M = M \oplus E(p)</math>, czyli zamieniając na ścieżce krawędzie wolne na skojarzone i na odwrót. Możemy pokazać także przeciwne wynikanie:
{{kotwica|ścieżka_powiększająca|'''Ścieżką powiększającą'''}} nazwiemy ścieżkę prostą <math>p</math> taką, że jej krawędzie są na przemian skojarzone i wolne, a końce są wolne. Łatwo zauważyć, że jeżeli istnieje ścieżka powiększająca <math>p</math> względem <math>M</math>, to <math>M</math> nie jest skojarzeniem maksymalnym. Używając wtedy ścieżki <math>p</math>, możemy skonstruować skojarzenie większe biorąc <math>M = M \oplus p</math>, czyli zamieniając na ścieżce krawędzie wolne na skojarzone i na odwrót. Możemy pokazać także przeciwne wynikanie:


{{twierdzenie|1 [Twierdzenie Berge'a]|twierdzenie_1|3= Skojarzenie <math>M</math> jest maksymalne gdy nie istnieje względem niego żadna ścieżka powiększająca. }}
{{twierdzenie|1 [Twierdzenie Berge'a o ścieżkach powiększających]|twierdzenie_1|3= Skojarzenie <math>M</math> jest maksymalne, gdy nie istnieje względem niego żadna ścieżka powiększająca. }}


{{dowod|||3= Załóżmy przeciwnie, że istnieje skojarzenie <math>M'</math> liczniejsze niż <math>M</math>. Rozważmy graf <math>G' = (V, M \oplus M')</math>. Zauważmy, że w <math>G'</math> każdy wierzchołek ma stopień co najwyżej <math>2</math>, w związku z tym <math>G'</math> składa się z rozłącznych ścieżek i cykli. Na każdym cyklu występuje tyle samo krawędzi z <math>M</math> co <math>M'</math>. Natomiast na ścieżkach może występować co najwyżej o jedną krawędź więcej z któregoś skojarzenia.  W grafie <math>G'</math> jest więcej krawędzi z <math>M'</math> niż z <math>M</math>, a zatem musi też istnieć ścieżka na której jest więcej krawędzi z <math>M'</math>. Musi to być oczywiście ścieżka powiększająca. }}
{{dowod|||3= Załóżmy przeciwnie, że istnieje skojarzenie <math>M'</math> liczniejsze niż <math>M</math>. Rozważmy graf <math>G' = (V, M \oplus M')</math>. Zauważmy, że w <math>G'</math> każdy wierzchołek ma stopień co najwyżej <math>2</math>, w związku z tym <math>G'</math> składa się z rozłącznych ścieżek i cykli. Na każdym cyklu występuje tyle samo krawędzi z <math>M</math> co <math>M'</math>. Natomiast w ścieżkach może występować co najwyżej o jedną krawędź więcej z któregoś skojarzenia.  W grafie <math>G'</math> jest więcej krawędzi z <math>M'</math> niż z <math>M</math>, a zatem musi też istnieć ścieżka, na której jest więcej krawędzi z <math>M'</math>. Musi to być oczywiście ścieżka powiększająca. }}




=== Algorytm wykorzystujący ścieżki powiększające ===
=== Algorytm wykorzystujący ścieżki powiększające ===


Zastanówmy się teraz jak efektywnie sprawdzić, czy w grafie dwudzielnym nie ma ścieżki powiększającej, bądź jeżeli jest to ją znaleźć. Dla grafu dwudzielnego <math>G=(V_1 \cup V_2, E)</math> oraz skojarzenia <math>M</math> zdefiniujmy skierowany graf <math>G_{M}= (v_1\cup V_2, {E}_M)</math> jako
Zastanówmy się teraz, jak efektywnie sprawdzić, czy w grafie dwudzielnym nie ma ścieżki powiększającej, bądź jeżeli jest, to jak ją znaleźć. Dla grafu dwudzielnego <math>G=(V_1 \cup V_2, E)</math> oraz skojarzenia <math>M</math> zdefiniujmy skierowany graf <math>G_{M}= (V_1\cup V_2, {E}_M)</math> jako




{{wzor2|1=
{{wzor2|1=
<math>
<math>
{E} = \{(v_1, v_2): v_1v_2 \in E, v_1 \in V_1, v_2 \in V_2\} \cup \{(v_2, v_1): \in M, v_1 \in V_1, v_2 \in V_2\}.
\begin{array}{r@{}c@{}l}
{E}_M &=& \{(v_1, v_2): v_1v_2 \in E, v_1 \in V_1, v_2 \in V_2\}\\
&\cup& \{(v_2, v_1): v_1v_2 \in M, v_1 \in V_1, v_2 \in V_2\}
\end{array}
</math>
</math>
}}
}}
Linia 29: Linia 32:


{{algorytm|znajdowania ścieżki powiększającej|algorytm_ścieżka_powiększająca|3=
{{algorytm|znajdowania ścieżki powiększającej|algorytm_ścieżka_powiększająca|3=
   ZNAJDŹ-ŚCIEŻKĘ-POWIĘKSZAJĄCĄ(G = (V_1 \cup V_2,E),M)
   ZNAJDŹ-ŚCIEŻKĘ-POWIĘKSZAJĄCĄ<math>(G = (V_1 \cup V_2,E),M)</math>
   1  <math>V_1' = </math> zbiór wierzchołków wolnych w <math>V_1</math>
   1  <math>V_1' =</math> zbiór wierzchołków wolnych w <math>V_1</math>
   2  <math>V_2' = </math> zbiór wierzchołków wolnych w <math>V_2</math>
   2  <math>V_2' =</math> zbiór wierzchołków wolnych w <math>V_2</math>
   3  skonstruuj graf skierowany <math>{G}_M = (V_1 \cup V_2, {E}_M)</math>
   3  skonstruuj graf skierowany <math>{G}_M = (V_1 \cup V_2, {E}_M)</math>
   5  znajdź ścieżkę <math>p</math> z <math>V_1'</math> do <math>V_2'</math> w <math>{G}_M</math>
   5  znajdź ścieżkę <math>p</math> z <math>V_1'</math> do <math>V_2'</math> w <math>{G}_M</math>
   6  '''if''' <math>p</math> nie istnieje '''then'''
   6  '''if''' <math>p</math> nie istnieje '''then'''
   7    '''return''' NIL ''(nie ma ścieżki powiększającej)''
   7    '''return''' <math>NIL</math> ''(nie ma ścieżki powiększającej)''
   8  '''return''' <math>p</math> ''(<math>p</math> to ścieżka powiększająca w <math>G</math>)''
   8 usuń cykle z <math>p</math> tak aby <math>p</math> była ścieżką prostą
  9 '''return''' <math>p</math> ''(<math>p</math> to ścieżka powiększająca w <math>G</math>)''
}}
}}


{{lemat|2|lemat_2|3= Powyższy algorytm znajduje ścieżkę <math>p</math> wtedy i tylko wtedy gdy w <math>G</math> istnieje ścieżka powiększająca względem <math>M</math>. Co więcej znaleziona ścieżka jest ścieżką powiększającą.}}
{{lemat|2|lemat_2|3= Powyższy algorytm znajduje ścieżkę <math>p</math> wtedy i tylko wtedy, gdy w <math>G</math> istnieje ścieżka powiększająca względem <math>M</math>. Co więcej, znaleziona ścieżka jest ścieżką powiększającą.}}


{{dowod|||3= Załóżmy, że ścieżka <math>p</math> istnieje i jest to ścieżka, która
{{dowod|||3= Załóżmy, że ścieżka <math>p</math> istnieje. Z konstrukcji algorytmu wiemy, że jest to ścieżka, która
# zaczyna się w wierzchołku wolnym,
# zaczyna się w wierzchołku wolnym,
# z <math>V_1</math> do <math>V_2</math> idzie krawędzią wolną,
# z <math>V_1</math> do <math>V_2</math> idzie krawędzią wolną,
Linia 47: Linia 51:
# kończy się w <math>V_2</math> krawędzią wolną.
# kończy się w <math>V_2</math> krawędzią wolną.


Ścieżka <math>p</math> spełnia wszystkie warunki dla [[#scieżka_powiększająca|ścieżki powiększającej]] oprócz bycia ścieżką prostą. Jeżeli <math>p</math> przechodzi dwa razy przez ten sam wierzchołek <math>v \in V_1</math>, to wchodzi do niego dwa razy krawędzią skojarzoną, a wychodzi krawędzią nieskojarzoną. Jeżeli teraz usuniemy kawałek ścieżki pomiędzy tymi dwoma wejściami do <math>v</math> to powyższe cztery warunki nadal będą zachodzić. Możemy więc zachowując je zamienić ścieżkę <math>p</math> na ścieżkę prostą.
Ścieżka <math>p</math> spełnia wszystkie warunki dla [[#scieżka_powiększająca|ścieżki powiększającej]] oprócz bycia ścieżką prostą. Jeżeli <math>p</math> przechodzi dwa razy przez ten sam wierzchołek <math>v \in V_1</math>, to wchodzi do niego dwa razy krawędzią skojarzoną, a wychodzi krawędzią nieskojarzoną. Jeżeli teraz usuniemy kawałek ścieżki pomiędzy tymi dwoma wejściami do <math>v</math> (linia 8) to powyższe cztery warunki nadal będą zachodzić. Możemy więc, zachowując je, zamienić ścieżkę <math>p</math> na ścieżkę prostą.


Natomiast jeżeli w grafie <math>G</math> jest ścieżka powiększająca względem <math>M</math> to możemy ją wprost przetłumaczyć na ścieżkę w gafie <math>{G}_M'</math>. }}
Natomiast jeżeli w grafie <math>G</math> jest ścieżka powiększająca względem <math>M</math>, to możemy ją wprost przetłumaczyć na ścieżkę w gafie <math>{G}_M</math>.}}






Jesteśmy już gotowi na konstrukcję pierwszego algorytmu znajdującego maksymalne skojarzenia w grafie dwudzielnym.
Jesteśmy już gotowi, aby skonstruować pierwszy algorytm znajdujący maksymalne skojarzenie w grafie dwudzielnym.


{{algorytm|znajdujący maksymalne skojarzenie w grafie dwudzielnym|algorytm_skojarzenia_1|3=
{{algorytm|znajdujący maksymalne skojarzenie w grafie dwudzielnym|algorytm_skojarzenia_1|3=
Linia 59: Linia 63:
   1  <math>M=\emptyset</math>
   1  <math>M=\emptyset</math>
   1  '''repeat'''
   1  '''repeat'''
   2    <math>p = </math>[[#algorytm_ścieżka_powiększająca|ZNAJDŹ-ŚCIEŻKĘ-POWIĘKSZAJĄCĄ]]<math> (G,M)</math>
   2    <math>p =</math>[[#algorytm_ścieżka_powiększająca|ZNAJDŹ-ŚCIEŻKĘ-POWIĘKSZAJĄCĄ]]<math>(G,M)</math>
   3    '''if''' <math>p \neq NIL</math> '''then'''
   3    '''if''' <math>p \neq NIL</math> '''then'''
   4      <math>M=M \oplus p</math>
   4      <math>M=M \oplus p</math>
Linia 68: Linia 72:
Wyszukiwanie ścieżki powiększającej zobrazowane jest na poniższej animacji.  
Wyszukiwanie ścieżki powiększającej zobrazowane jest na poniższej animacji.  


<flash>file=Zasd_Ilustr_d.swf |width=600|height=300</flash>
[[File:Zasd_ilustr_d.svg|800x300px|thumb|center]]
 
Poprawność tego algorytmu wynika z [[#lemat_2|Lematu 2]] oraz [[#twierdzenie_bergea|Twierdzenia Berge'a]]. Ponieważ <math>\frac{|V|}{2}</math> jest ograniczeniem górnym na rozmiar maksymalnego skojarzenia, a w każdym kroku pętli rozmiar skojarzenia rośnie o <math>1</math>, to pętla ta zostanie wykonana co najwyżej <math>O(|V|)</math> razy. Wyszukanie jednej ścieżki powiększającej zajmuje czas <math>O(|E|)</math>, a więc całkowity czas działania algorytmu to <math>O(|V||E|)</math>.
Poprawność tego algorytmu wynika z [[#lemat_2|Lematu 2]] oraz [[#twierdzenie_bergea|Twierdzenia Berge'a]]. Ponieważ <math>\frac{|V|}{2}</math> jest ograniczeniem górnym na rozmiar maksymalnego skojarzenia, a w każdym kroku pętli rozmiar skojarzenia rośnie o <math>1</math>, to pętla ta zostanie wykonana co najwyżej <math>O(|V|)</math> razy. Wyszukanie jednej ścieżki powiększającej zajmuje czas <math>O(|E|)</math>, a więc całkowity czas działania algorytmu to <math>O(|V||E|)</math>.


Linia 75: Linia 78:




Algorytm Hopcrofta-Karpa także wykorzystuje technikę ścieżek powiększających. Jednak w celu przyśpieszenia działania tej metody, zamiast wyszukiwać ścieżki pojedynczo, będziemy szukać wielu ścieżek na raz. Będziemy to robić jednak w taki sposób aby długości tych ścieżek systematycznie rosły, będziemy mogli skorzystać wtedy z następującego lematu, który mówi, że długich ścieżek jest.
Algorytm Hopcrofta-Karpa także wykorzystuje technikę ścieżek powiększających. Jednak w celu przyśpieszenia działania tej metody, zamiast wyszukiwać ścieżki pojedynczo, będziemy szukać wielu ścieżek na raz. Będziemy to robić jednak w taki sposób, aby długości tych ścieżek systematycznie rosły, będziemy mogli skorzystać wtedy z następującego lematu, który mówi, że długich ścieżek jest mało.


{{lemat|3|lemat_3|3=
{{lemat|3|lemat_3|3=
Linia 82: Linia 85:
{{dowod|||3=
{{dowod|||3=
Podobnie jak w dowodzie [[#twierdzenie_1|Twierdzenia Berge'a]] rozważmy graf <math>G' = (V, M \oplus M')</math>. Graf ten zawiera co najwyżej <math>|M^*| - |M|</math> ścieżek powiększających względem
Podobnie jak w dowodzie [[#twierdzenie_1|Twierdzenia Berge'a]] rozważmy graf <math>G' = (V, M \oplus M')</math>. Graf ten zawiera co najwyżej <math>|M^*| - |M|</math> ścieżek powiększających względem
<math>M</math>, długość każdej z tych ścieżek musi być co najmniej <math>k</math>. Sumaryczna długość tych ścieżek nie przekracza <math>|V|</math>, a wiec nie może ich być więcej niż <math>\frac{|V|}{k}</math>.
<math>M</math>, długość każdej z tych ścieżek musi być co najmniej <math>k</math>. Sumaryczna długość tych ścieżek nie przekracza <math>|V|</math>, a więc nie może ich być więcej niż <math>\frac{|V|}{k}</math>.
}}
}}


=== Maksymalny zbiór rozłącznych wierzchołkowy ścieżek powiększających ===
=== Maksymalny zbiór rozłącznych wierzchołkowy ścieżek powiększających ===
 
{{kotwica|max_ścieżki|}}
W celu zagwarantowania wzrostu długości ścieżek po każdej fazie będziemy wyszukiwać maksymalnego zbioru rozłącznych wierzchołkowo najkrótszych ścieżek powiększających <math>P</math>. Pokażemy teraz, że po powiększeniu skojarzenia przy pomocy wszystkich tych ścieżek długość najkrótszej ścieżki rośnie. Oznaczmy przez <math>M \oplus P = M \oplus \bigoplus_{p\in P} p</math>.
W celu zagwarantowania wzrostu długości ścieżek po każdej fazie będziemy w każdej fazie konstruuować maksymalny zbiór rozłącznych wierzchołkowo najkrótszych ścieżek powiększających <math>P</math>. Pokażemy teraz, że po powiększeniu skojarzenia przy pomocy wszystkich tych ścieżek długość najkrótszej ścieżki rośnie. Oznaczmy przez <math>M \oplus P = M \oplus \bigoplus_{p\in P} p</math>.


{{lemat|4|lemat_4|3=
{{lemat|4|lemat_4|3=
Linia 94: Linia 97:


{{dowod|||3=
{{dowod|||3=
Weźmy najkrótszą ścieżkę powiększająca <math>\pi'</math> względem <math>M\oplus P</math>. Ścieżka ta musi przecinać się ze pewną ścieżką <math>\pi</math> ze zbioru <math>P</math> inaczej mówilibyśmy powiększyć <math>P</math> o <math>\pi</math>. Pokażemy teraz, że <math>|\pi'| \ge |\pi| +1</math>.
Weźmy najkrótszą ścieżkę powiększająca <math>\pi'</math> względem <math>M\oplus P</math>. Ścieżka ta musi przecinać się z pewną ścieżką <math>\pi_1</math> ze zbioru <math>P</math>, inaczej musielibyśmy powiększyć <math>P</math> o <math>\pi_1</math>. Pokażemy teraz, że <math>|\pi'| \ge |\pi_1| +1</math>. Kolejne fazy tego dowodu zobrazowane są na animacji poniżej.
 
[[File:Zasd_ilustr_o.svg|800x300px|thumb|center]]
Niech <math>u_1</math> i <math>u_2</math> będą odpowiednio pierwszym i ostatnim wierzchołkiem wspólnym dla ścieżek <math>\pi</math> i <math>\pi'</math>. Natomiast niech <math>v_1</math> będzie początkiem ścieżki <math>\pi</math>, a <math>v_2</math> jej końcem. Podobnie niech <math>v_1'</math> i <math>v_2'</math> będą początkiem i końcem ścieżki <math>\pi'</math>. Ze ścieżek <math>\pi</math> i <math>\pi'</math> możemy skonstruować dwie nowe ścieżki <math>R_1</math> i <math>R_2</math>. Niech <math>R_i</math> idzie kawałkiem ścieżki <math>\pi</math>z <math>v_i</math> do <math>u_i</math>, a następnie kawałkiem ścieżki <math>\pi'</math> z <math>u_i</math> do <math>v_i'</math>. Sumaryczna długość ścieżek <math>R_1</math> i <math>R_2</math> jest mniejsza o co najmniej <math>1</math> od długości ścieżek <math>\pi</math> i <math>\pi'</math>, możemy wiec zapisać:
Musimy jednak pamiętać, że ścieżka <math>\pi'</math> może przecinać więcej niż jedną ścieżkę z <math>P</math>. Załóżmy, że ścieżka <math>\pi'</math> przecina niektóre ścieżki z <math>P</math> w następującej kolejności: <math>\pi_1, \pi_2, \ldots, \pi_t</math>. Zauważmy, że z tych ścieżek i ścieżki <math>\pi'</math> możemy skonstruować zbiór <math>t+1</math> nowych ścieżek. Ścieżkę <math>R_1</math> konstruujemy biorąc początek ścieżki <math>\pi'</math>, a następnie kawałek ścieżki <math>\pi_1</math>. Ścieżkę <math>R_i</math>, dla <math>i=2,\ldots,t</math>, konstruujemy biorąc kawałek ścieżki <math>\pi_i</math>, następnie kawałek ścieżki <math>\pi'</math>, a potem kawałek ścieżki <math>\pi_{i+1}</math>. Ostatnią ze ścieżek <math>R_{t+1}</math> konstruujemy biorąc kawałek ścieżki <math>\pi_t</math> i koniec ścieżki <math>\pi'</math>. Sumaryczna długość ścieżek <math>R_i</math> jest o co najmniej <math>1</math> mniejsza niż sumaryczna długość ścieżek <math>\pi_i'</math> i ścieżki <math>\pi'</math>. Możemy więc zapisać:




{{wzor2|1=
{{wzor2|1=
<math>
<math>
|R_1| + |R_2| + 1 \le |\pi| + |\pi'|.
1+ \sum_{i=1}^{t+1}|R_i| \le |\pi'| + \sum_{i=1}^{t}|\pi_i| = |\pi'| + t |\pi_1| .
</math>
</math>
}}
}}


Zauważmy, że ścieżki te są ścieżkami powiększającymi względem <math>M</math>. Ich długości muszą być co najmniej takie jak długość ścieżki <math>\pi</math> i:
Zauważmy, że ścieżki <math>R_i</math> są ścieżkami powiększającymi względem <math>M</math>. Ich długości muszą być co najmniej takie, jak długość ścieżek <math>\pi_i</math> i:




{{wzor2|1=
{{wzor2|1=
<math>
<math>
  1 \le - |\pi| + |\pi'|,
  1 \le - |\pi_1| + |\pi'|</math>,
</math>
}}
}}


co kończy dowód lematu.
co kończy dowód lematu.  
}}
}}


Linia 130: Linia 132:
}}
}}


Procedura ta różni się od standardowej procedury DFS dwoma rzeczami. Po pierwsze prowadzi wyszukiwanie tylko do momentu znalezienia wierzchołka z <math>T</math>. Po drugie po zakończonym wyszukiwaniu usuwa wszystkie odwiedzone wierzchołki, tak aby każda następna znaleziona ścieżka przez nie nie przechodziła. Procedurę tą wykorzystamy do grafu warstwowego <math>\overline{G}_M</math>skonstruowanego z grafu <math>{G}_M</math>. Niech <math>V_1'</math> oznacza zbiór wierzchołków wolnych w <math>V_1</math>. Oznaczmy przez <math>d:V \to \mathcal{N}</math> odległość <math>d(v)</math>wierzchołka <math>v</math> od wierzchołków z <math>V_1'</math>. Graf <math>\overline{G}_M = (V_1\cup V_2, \overline{E}_M)</math> ma następujący zbiór krawędzi:
Procedura ta różni się od standardowej procedury DFS w dwóch aspektach. Po pierwsze, prowadzi wyszukiwanie tylko do momentu znalezienia wierzchołka ze zbioru <math>T</math>. Po drugie, po zakończonym wyszukiwaniu usuwa wszystkie odwiedzone wierzchołki, tak aby każda następna znaleziona ścieżka przez nie nie przechodziła. Procedurę tę zastosujemy do grafu warstwowego <math>\overline{G}_M</math>skonstruowanego z grafu <math>{G}_M</math>. Niech <math>V_1'</math> oznacza zbiór wierzchołków wolnych w <math>V_1</math>. Oznaczmy przez <math>d:V \to \mathcal{N}</math> odległość <math>d(v)</math> wierzchołka <math>v</math> od wierzchołków z <math>V_1'</math>. Graf <math>\overline{G}_M = (V_1\cup V_2, \overline{E}_M)</math> ma następujący zbiór krawędzi:


{{wzor2|1=
{{wzor2|1=
Linia 140: Linia 142:


{{lemat|5|lemat_5|3=
{{lemat|5|lemat_5|3=
Każda ścieżka w grafie <math>\overline{G}_M</math> zaczynająca się w <math>V_1'</math> jest najkrótszą ścieżką w grafie <math>G_M</math>.
Każda ścieżka w grafie <math>\overline{G}_M</math>, zaczynająca się w <math>V_1'</math>, jest najkrótszą ścieżką w grafie <math>G_M</math>.
}}
}}
{{dowod|||3=
{{dowod|||3=
Lemat ten wynika wprost z definicji najkrótszej ścieżki, tzn. ścieżka jest najkrótsza jeżeli jej długość jest równa odległości z jej początku do jej końca.
Lemat ten wynika wprost z definicji najkrótszej ścieżki, tzn. ścieżka jest najkrótsza, jeżeli jej długość jest równa odległości z jej początku do jej końca.
}}
}}


Lemat ten pozwala nam na konstrukcję następującego algorytmu wyszukującego maksymalny zbiór wierzchołkowo rozłącznych najkrótszych ścieżek powiększających.
Lemat ten pozwala nam na konstrukcję następującego algorytmu, wyszukującego maksymalny zbiór wierzchołkowo rozłącznych najkrótszych ścieżek powiększających.


{{algorytm|znajdujący maksymalny zbiór wierzchołkowo rozłącznych najkrótszych ścieżek powiększających|algorytm_max_ścieżki|3=
{{algorytm|znajdujący maksymalny zbiór wierzchołkowo rozłącznych najkrótszych ścieżek powiększających|algorytm_max_ścieżki|3=
   MAKSYMALNY-ZBIÓR-NAJKRÓTSZYCH-ŚCIEŻEK(G = (V_1 \cup V_2,E),M)
   MAKSYMALNY-ZBIÓR-NAJKRÓTSZYCH-ŚCIEŻEK<math>(G = (V_1 \cup V_2,E),M)</math>
   1  <math>P=\emptyset</math>
   1  <math>P=\emptyset</math>
   2  skonstruuj graf <math>\overline{G}_M = (V_1\cup V_2,\overline{E}_M)</math>
   2  skonstruuj graf <math>\overline{G}_M = (V_1\cup V_2,\overline{E}_M)</math>
Linia 155: Linia 157:
   4  '''for''' <math>v \in V_1'</math> '''do'''
   4  '''for''' <math>v \in V_1'</math> '''do'''
   5  '''begin'''
   5  '''begin'''
   6    <math>p = </math>[[#algorytm_częściowe_DFS|CZĘŚCIOWE-DFS]]<math>(G, v , T)</math>
   6    <math>p =</math>[[#algorytm_częściowe_DFS|CZĘŚCIOWE-DFS]]<math>(G, v , T)</math>
   7    '''if''' <math>p\neq NIL</math> '''then'''
   7    '''if''' <math>p\neq NIL</math> '''then'''
   8      <math>P = P \cup p</math>  
   8      <math>P = P \cup p</math>  
Linia 163: Linia 165:


{{lemat|6|lemat_6|3=
{{lemat|6|lemat_6|3=
Algorytm MAKSYMALNY-ZBIÓR-NAJKRÓTSZYCH-ŚCIEŻEK znajduje maksymalny zbiór wierzchołkowo rozłącznych ścieżek powiększających względem <math>M</math> w czasie <math>O(E)</math>.
Algorytm [[#algorytm_max_ścieżki|MAKSYMALNY-ZBIÓR-NAJKRÓTSZYCH-ŚCIEŻEK]] znajduje maksymalny zbiór wierzchołkowo rozłącznych najkrótszych ścieżek powiększających względem <math>M</math> w czasie <math>O(|E|)</math>.
}}
}}


{{dowod|||3=
{{dowod|||3=
Zauważmy, że czas działania <math>O(|E|)</math> algorytmu wynika z konstrukcji CZĘŚCIOWE-DFS, która rozpatruje każdy wierzchołek tylko raz, a zatem także każda krawędź rozpatrywana jest tylko raz. Co więcej usuwanie przejrzanych wierzchołków gwarantuje, że <math>P</math> zawiera ścieżki wierzchołkowo rozłączne. To, że są to ścieżki najkrótsze wynika natomiast z [[#lemat_5|Lematu 5]].
Zauważmy, że czas działania <math>O(|E|)</math> algorytmu wynika z konstrukcji CZĘŚCIOWE-DFS, która rozpatruje każdy wierzchołek tylko raz, a zatem także każda krawędź rozpatrywana jest tylko raz. Co więcej, usuwanie przejrzanych wierzchołków gwarantuje, że <math>P</math> zawiera ścieżki wierzchołkowo rozłączne. To, że są to ścieżki najkrótsze wynika natomiast z [[#lemat_5|Lematu 5]].
}}
}}


Linia 175: Linia 177:


{{algorytm|Hopcrofta-Karpa|algorytm_hopcrofta-karpa|3=
{{algorytm|Hopcrofta-Karpa|algorytm_hopcrofta-karpa|3=
   HOPCROFT-KARP(G = (V_1 \cup V_2))
   HOPCROFT-KARP<math>(G = (V_1 \cup V_2,E))</math>
   1  <math>M = \emptyset</math>
   1  <math>M = \emptyset</math>
   2  '''repeat'''
   2  '''repeat'''
Linia 182: Linia 184:
   5      <math>M = M \oplus P</math>
   5      <math>M = M \oplus P</math>
   6  '''until''' <math>P = NIL</math>
   6  '''until''' <math>P = NIL</math>
   7  '''return''' M
   7  '''return''' <math>M</math>
}}
}}


<flash>file=Zasd_Ilustr_h.swf |width=600|height=300</flash>
[[File:Zasd_ilustr_h.svg|800x300px|thumb|center]]
 
{{twierdzenie|7|twierdzenie_7|3=
{{twierdzenie|7|twierdzenie_7|3=
Algorytm Hopcrofta-Karpa znajduje maksymalne skojarzenie w grafie dwudzielnym w czasie <math>O(\sqrt{n}m)</math>.
Algorytm Hopcrofta-Karpa znajduje maksymalne skojarzenie w grafie dwudzielnym w czasie <math>O(\sqrt{|V|}|E|)</math>.
}}
}}


Linia 194: Linia 195:
Poprawność algorytmu wynika z [[#twierdzenie_1|Twierdzenia Berge'a]] ponieważ, jeżeli graf zawiera ścieżkę powiększającą, to zbiór <math>P</math> nie będzie pusty.  
Poprawność algorytmu wynika z [[#twierdzenie_1|Twierdzenia Berge'a]] ponieważ, jeżeli graf zawiera ścieżkę powiększającą, to zbiór <math>P</math> nie będzie pusty.  


[[#lemat_4|Lemat 4]] mówi, że po każdym wykonaniu głównej pętli algorytmu długość najkrótszej ścieżki powiększającej jest większa o co najmniej 1. Dlatego po <math>\sqrt{|V|}</math> krokach wynosić będzie ona co najmniej <math>\sqrt{|V|}</math>. Z [[#lemat_3|Lematu 3]] wiemy, że w takim wypadku pozostało nam jeszcze nie więcej niż <math>\sqrt{|V|}</math> ścieżek do znalezienia i zostanie jeszcze wykonanych co najwyżej <math>\sqrt{|V|}</math> obrotów pętli. W sumie pętla wykonana  będzie nie więcej niż <math>2\sqrt{|V|}</math> razy. Każde wykonanie pętli zajmuje czas <math>O(|E|)</math> ([[#lemat_6|Lemat 6]], a więc całkowity czas działania algorytmu wynosi <math>O(\sqrt{|V|}|E|)</math>.
[[#lemat_4|Lemat 4]] mówi, że po każdym wykonaniu głównej pętli algorytmu długość najkrótszej ścieżki powiększającej jest większa o co najmniej 1. Dlatego po <math>\sqrt{|V|}</math> krokach wynosić będzie ona co najmniej <math>\sqrt{|V|}</math>. Z [[#lemat_3|Lematu 3]] wiemy, że w takim wypadku pozostało nam jeszcze nie więcej niż <math>\sqrt{|V|}</math> ścieżek do znalezienia i zostanie jeszcze wykonanych co najwyżej <math>\sqrt{|V|}</math> obrotów pętli. W sumie pętla wykonana  będzie nie więcej niż <math>2\sqrt{|V|}</math> razy. Każde wykonanie pętli zajmuje czas <math>O(|E|)</math> ([[#lemat_6|Lemat 6]]), a więc całkowity czas działania algorytmu wynosi <math>O(\sqrt{|V|}|E|)</math>.
}}
}}

Aktualna wersja na dzień 22:15, 11 wrz 2023

Abstrakt

W wykładzie tym skoncentrujemy się na problemie znajdowania najliczniejszych skojarzeń w grafach dwudzielnych. Zaczniemy od przedstawienia idei ścieżek powiększających, a następie użyjemy jej do konstrukcji algorytmu znajdującego maksymalne skojarzenie w grafie G=(V,E) w czasie O(|V||E|). Następnie przedstawimy algorytm Hopcrofta-Karpa, który działać będzie w czasie O(|V||E|).

Problem maksymalnego skojarzenia w grafie dwudzielnym

Niech G=(V,E) będzie grafem nieskierowanym. Skojarzeniem w grafie G nazywamy każdy podzbiór krawędzi ME taki, w którym co najwyżej jedna krawędź z M jest incydentna z każdym wierzchołkiem w V. O wierzchołku v incydentnym do pewniej krawędzi z M mówimy, że jest skojarzony, w przeciwnym przypadku v nazywamy wolnym. Podobnie jeżeli krawędź e należy do skojarzenia, mówimy, że jest ona skojarzona a w przeciwnym wypadku mówimy, że jest to krawędź wolna. Skojarzenie M nazywamy maksymalnym gdy ma ono największą liczność spośród skojarzeń w G. W trakcie tego wykładu zajmiemy się tylko problemem znajdowania skojarzeń w grafach dwudzielnych, czyli takich, w których zbiór wierzchołków można podzielić na V=V1V2, gdzie V1 i V2 są rozłączne, a wszystkie krawędzie z E prowadzą pomiędzy V1 i V2.

Ścieżki powiększające

Ścieżką powiększającą nazwiemy ścieżkę prostą p taką, że jej krawędzie są na przemian skojarzone i wolne, a końce są wolne. Łatwo zauważyć, że jeżeli istnieje ścieżka powiększająca p względem M, to M nie jest skojarzeniem maksymalnym. Używając wtedy ścieżki p, możemy skonstruować skojarzenie większe biorąc M=Mp, czyli zamieniając na ścieżce krawędzie wolne na skojarzone i na odwrót. Możemy pokazać także przeciwne wynikanie:

Twierdzenie 1 [Twierdzenie Berge'a o ścieżkach powiększających]

Skojarzenie M jest maksymalne, gdy nie istnieje względem niego żadna ścieżka powiększająca.

Dowód

Załóżmy przeciwnie, że istnieje skojarzenie M liczniejsze niż M. Rozważmy graf G=(V,MM). Zauważmy, że w G każdy wierzchołek ma stopień co najwyżej 2, w związku z tym G składa się z rozłącznych ścieżek i cykli. Na każdym cyklu występuje tyle samo krawędzi z M co M. Natomiast w ścieżkach może występować co najwyżej o jedną krawędź więcej z któregoś skojarzenia. W grafie G jest więcej krawędzi z M niż z M, a zatem musi też istnieć ścieżka, na której jest więcej krawędzi z M. Musi to być oczywiście ścieżka powiększająca.


Algorytm wykorzystujący ścieżki powiększające

Zastanówmy się teraz, jak efektywnie sprawdzić, czy w grafie dwudzielnym nie ma ścieżki powiększającej, bądź jeżeli jest, to jak ją znaleźć. Dla grafu dwudzielnego G=(V1V2,E) oraz skojarzenia M zdefiniujmy skierowany graf GM=(V1V2,EM) jako


Parser nie mógł rozpoznać (nieznana funkcja „\begin{array}”): {\displaystyle \begin{array}{r@{}c@{}l} {E}_M &=& \{(v_1, v_2): v_1v_2 \in E, v_1 \in V_1, v_2 \in V_2\}\\ &\cup& \{(v_2, v_1): v_1v_2 \in M, v_1 \in V_1, v_2 \in V_2\} \end{array} }


Algorytm znajdowania ścieżki powiększającej


 ZNAJDŹ-ŚCIEŻKĘ-POWIĘKSZAJĄCĄ(G=(V1V2,E),M)
 1  V1= zbiór wierzchołków wolnych w V1
 2  V2= zbiór wierzchołków wolnych w V2
 3  skonstruuj graf skierowany GM=(V1V2,EM)
 5  znajdź ścieżkę p z V1 do V2 w GM
 6  if p nie istnieje then
 7    return NIL (nie ma ścieżki powiększającej)
 8  usuń cykle z p tak aby p była ścieżką prostą
 9  return p (p to ścieżka powiększająca w G)

Lemat 2

Powyższy algorytm znajduje ścieżkę p wtedy i tylko wtedy, gdy w G istnieje ścieżka powiększająca względem M. Co więcej, znaleziona ścieżka jest ścieżką powiększającą.

Dowód

Załóżmy, że ścieżka p istnieje. Z konstrukcji algorytmu wiemy, że jest to ścieżka, która
  1. zaczyna się w wierzchołku wolnym,
  2. z V1 do V2 idzie krawędzią wolną,
  3. z V2 do V1 wraca krawędzią skojarzoną,
  4. kończy się w V2 krawędzią wolną.

Ścieżka p spełnia wszystkie warunki dla ścieżki powiększającej oprócz bycia ścieżką prostą. Jeżeli p przechodzi dwa razy przez ten sam wierzchołek vV1, to wchodzi do niego dwa razy krawędzią skojarzoną, a wychodzi krawędzią nieskojarzoną. Jeżeli teraz usuniemy kawałek ścieżki pomiędzy tymi dwoma wejściami do v (linia 8) to powyższe cztery warunki nadal będą zachodzić. Możemy więc, zachowując je, zamienić ścieżkę p na ścieżkę prostą.

Natomiast jeżeli w grafie G jest ścieżka powiększająca względem M, to możemy ją wprost przetłumaczyć na ścieżkę w gafie GM.


Jesteśmy już gotowi, aby skonstruować pierwszy algorytm znajdujący maksymalne skojarzenie w grafie dwudzielnym.

Algorytm znajdujący maksymalne skojarzenie w grafie dwudzielnym


 MAKSYMALNE-SKOJARZENIE(G = (V_1 \cup V_2,E))
 1  M=
 1  repeat
 2    p=ZNAJDŹ-ŚCIEŻKĘ-POWIĘKSZAJĄCĄ(G,M)
 3    if pNIL then
 4      M=Mp
 6  until p=NIL
 5  return M

Wyszukiwanie ścieżki powiększającej zobrazowane jest na poniższej animacji.

Plik:Zasd ilustr d.svg

Poprawność tego algorytmu wynika z Lematu 2 oraz Twierdzenia Berge'a. Ponieważ |V|2 jest ograniczeniem górnym na rozmiar maksymalnego skojarzenia, a w każdym kroku pętli rozmiar skojarzenia rośnie o 1, to pętla ta zostanie wykonana co najwyżej O(|V|) razy. Wyszukanie jednej ścieżki powiększającej zajmuje czas O(|E|), a więc całkowity czas działania algorytmu to O(|V||E|).

Algorytm Hopcrofta-Karpa

Algorytm Hopcrofta-Karpa także wykorzystuje technikę ścieżek powiększających. Jednak w celu przyśpieszenia działania tej metody, zamiast wyszukiwać ścieżki pojedynczo, będziemy szukać wielu ścieżek na raz. Będziemy to robić jednak w taki sposób, aby długości tych ścieżek systematycznie rosły, będziemy mogli skorzystać wtedy z następującego lematu, który mówi, że długich ścieżek jest mało.

Lemat 3

Niech M* będzie skojarzeniem maksymalnym, a M pewnym dowolnym skojarzeniem w G. Jeżeli długość najkrótszej ścieżki powiększającej względem M wynosi k, to |M*||M||V|k.

Dowód

Podobnie jak w dowodzie Twierdzenia Berge'a rozważmy graf G=(V,MM). Graf ten zawiera co najwyżej |M*||M| ścieżek powiększających względem M, długość każdej z tych ścieżek musi być co najmniej k. Sumaryczna długość tych ścieżek nie przekracza |V|, a więc nie może ich być więcej niż |V|k.

Maksymalny zbiór rozłącznych wierzchołkowy ścieżek powiększających

W celu zagwarantowania wzrostu długości ścieżek po każdej fazie będziemy w każdej fazie konstruuować maksymalny zbiór rozłącznych wierzchołkowo najkrótszych ścieżek powiększających P. Pokażemy teraz, że po powiększeniu skojarzenia przy pomocy wszystkich tych ścieżek długość najkrótszej ścieżki rośnie. Oznaczmy przez MP=MpPp.

Lemat 4

Niech P będzie maksymalnym rozłącznym wierzchołkowo zbiorem najkrótszych ścieżek powiększających względem M, wtedy długość najkrótszej ścieżki powiększającej względem MP jest większa niż długość najkrótszej ścieżki powiększającej względem M.

Dowód

Weźmy najkrótszą ścieżkę powiększająca π względem MP. Ścieżka ta musi przecinać się z pewną ścieżką π1 ze zbioru P, inaczej musielibyśmy powiększyć P o π1. Pokażemy teraz, że |π||π1|+1. Kolejne fazy tego dowodu zobrazowane są na animacji poniżej.
Plik:Zasd ilustr o.svg

Musimy jednak pamiętać, że ścieżka π może przecinać więcej niż jedną ścieżkę z P. Załóżmy, że ścieżka π przecina niektóre ścieżki z P w następującej kolejności: π1,π2,,πt. Zauważmy, że z tych ścieżek i ścieżki π możemy skonstruować zbiór t+1 nowych ścieżek. Ścieżkę R1 konstruujemy biorąc początek ścieżki π, a następnie kawałek ścieżki π1. Ścieżkę Ri, dla i=2,,t, konstruujemy biorąc kawałek ścieżki πi, następnie kawałek ścieżki π, a potem kawałek ścieżki πi+1. Ostatnią ze ścieżek Rt+1 konstruujemy biorąc kawałek ścieżki πt i koniec ścieżki π. Sumaryczna długość ścieżek Ri jest o co najmniej 1 mniejsza niż sumaryczna długość ścieżek πi i ścieżki π. Możemy więc zapisać:


1+i=1t+1|Ri||π|+i=1t|πi|=|π|+t|π1|.

Zauważmy, że ścieżki Ri są ścieżkami powiększającymi względem M. Ich długości muszą być co najmniej takie, jak długość ścieżek πi i:


1|π1|+|π|,
co kończy dowód lematu.

Zajmijmy się teraz algorytmem konstrukcji zbioru ścieżek P. W konstrukcji tej użyjemy trochę zmodyfikowanej procedury DFS.

Algorytm częściowego DFS


 CZĘŚCIOWE-DFS(G,v,T)
 1  uruchom DFS(G,v) aż do momentu znalezienia pierwszego wierzchołka ze zbioru T
 2  usuń wszystkie odwiedzone wierzchołki w procedurze DFS z grafu G
 2  if istnieje ścieżka p z v do T then
 4    return p
 5  else
 6    return NIL

Procedura ta różni się od standardowej procedury DFS w dwóch aspektach. Po pierwsze, prowadzi wyszukiwanie tylko do momentu znalezienia wierzchołka ze zbioru T. Po drugie, po zakończonym wyszukiwaniu usuwa wszystkie odwiedzone wierzchołki, tak aby każda następna znaleziona ścieżka przez nie nie przechodziła. Procedurę tę zastosujemy do grafu warstwowego GMskonstruowanego z grafu GM. Niech V1 oznacza zbiór wierzchołków wolnych w V1. Oznaczmy przez d:V𝒩 odległość d(v) wierzchołka v od wierzchołków z V1. Graf GM=(V1V2,EM) ma następujący zbiór krawędzi:

EM={(u,v):(u,v)EM i d(u)+1=d(v)}.


Lemat 5

Każda ścieżka w grafie GM, zaczynająca się w V1, jest najkrótszą ścieżką w grafie GM.

Dowód

Lemat ten wynika wprost z definicji najkrótszej ścieżki, tzn. ścieżka jest najkrótsza, jeżeli jej długość jest równa odległości z jej początku do jej końca.

Lemat ten pozwala nam na konstrukcję następującego algorytmu, wyszukującego maksymalny zbiór wierzchołkowo rozłącznych najkrótszych ścieżek powiększających.

Algorytm znajdujący maksymalny zbiór wierzchołkowo rozłącznych najkrótszych ścieżek powiększających


 MAKSYMALNY-ZBIÓR-NAJKRÓTSZYCH-ŚCIEŻEK(G=(V1V2,E),M)
 1  P=
 2  skonstruuj graf GM=(V1V2,EM)
 3  niech V1 będzie zbiorem wierzchołków wolnych w V1
 4  for vV1 do
 5  begin
 6    p=CZĘŚCIOWE-DFS(G,v,T)
 7    if pNIL then
 8      P=Pp 
 9  end
 10 return P

Lemat 6

Algorytm MAKSYMALNY-ZBIÓR-NAJKRÓTSZYCH-ŚCIEŻEK znajduje maksymalny zbiór wierzchołkowo rozłącznych najkrótszych ścieżek powiększających względem M w czasie O(|E|).

Dowód

Zauważmy, że czas działania O(|E|) algorytmu wynika z konstrukcji CZĘŚCIOWE-DFS, która rozpatruje każdy wierzchołek tylko raz, a zatem także każda krawędź rozpatrywana jest tylko raz. Co więcej, usuwanie przejrzanych wierzchołków gwarantuje, że P zawiera ścieżki wierzchołkowo rozłączne. To, że są to ścieżki najkrótsze wynika natomiast z Lematu 5.

Algorytm

Zapiszmy teraz algorytm Hopcrofta-Karpa.

Algorytm Hopcrofta-Karpa


 HOPCROFT-KARP(G=(V1V2,E))
 1  M=
 2  repeat
 3    P=MAKSYMALNY-ZBIÓR-NAJKRÓTSZYCH-ŚCIEŻEK(G=(V1V2,E),M)
 4    if PNIL then
 5      M=MP
 6  until P=NIL
 7  return M
Plik:Zasd ilustr h.svg

Twierdzenie 7

Algorytm Hopcrofta-Karpa znajduje maksymalne skojarzenie w grafie dwudzielnym w czasie O(|V||E|).

Dowód

Poprawność algorytmu wynika z Twierdzenia Berge'a ponieważ, jeżeli graf zawiera ścieżkę powiększającą, to zbiór P nie będzie pusty. Lemat 4 mówi, że po każdym wykonaniu głównej pętli algorytmu długość najkrótszej ścieżki powiększającej jest większa o co najmniej 1. Dlatego po |V| krokach wynosić będzie ona co najmniej |V|. Z Lematu 3 wiemy, że w takim wypadku pozostało nam jeszcze nie więcej niż |V| ścieżek do znalezienia i zostanie jeszcze wykonanych co najwyżej |V| obrotów pętli. W sumie pętla wykonana będzie nie więcej niż 2|V| razy. Każde wykonanie pętli zajmuje czas O(|E|) (Lemat 6), a więc całkowity czas działania algorytmu wynosi O(|V||E|).