wersja do druku
Transkrypt
wersja do druku
Podstawowe algorytmy grafowe i ich zastosowania dr Andrzej Mróz (UMK w Toruniu) 2013 Projekt wspóªnansowany ze ±rodków Unii Europejskiej w ramach Europejskiego Funduszu Spoªecznego Projekt pn. Wzmocnienie potencjaªu dydaktycznego UMK w Toruniu w dziedzinach matematyczno-przyrodniczych Poddziaªanie 4.1.1 Programu Operacyjnego Kapitaª Ludzki 2 Spis tre±ci 3 1 Wst¦p 1.1 Przeszukiwanie grafu Przeszukiwanie (przegl¡danie) grafu = systematyczne przechodzenie wzdªu» jego kraw¦dzi w celu odwiedzenia wszystkich wierzchoªków. • Sªu»y m.in. do zbierania informacji o strukturze grafu. • Algorytmy grafowe cz¦sto zaczyna si¦ od przeszukania wej±ciowego grafu. • Wiele bardziej zaawansowanych algorytmów grafowych jest modykacj¡ podstawowych algorytmów przeszukiwania. Dwie metody przeszukiwania grafu: • w gª¡b (ang. • wszerz (ang. depth-rst search, DFS), breadth-rst search, BFS). W obu metodach b¦dziemy iterowa¢ po s¡siadach danego wierzchoªka. Dlatego najwygodniejsz¡ reprezentacj¡ grafu s¡ listy s¡siedztwa. Oznaczenia: dla u∈V, Adj = tablica list s¡siedztwa; Adj[u] = lista s¡siadów Uwaga. u w grae G. Iteracj¦ po s¡siadach danego wierzchoªka mo»na ªatwo zrealizowa¢ równie» na macierzy s¡siedztwa. Jest to jednak bardziej kosztowne w sensie zªo»ono±ci obliczeniowej. 2 DFS 2.1 Przeszukiwanie grafu w gª¡b Ustalmy graf niezorientowany Z ustalonego wierzchoªka G = (V, E). ¹ródªowego w si¦gamy coraz gª¦biej w graf, je»eli jest to tylko mo»liwe. • badamy wszystkie niezbadane dot¡d kraw¦dzie ostatnio odwiedzonego wierzchoªka • gdy wszystkie kraw¦dzie v s¡ zbadane, wracamy do wierzchoªka, z którego v v, zostaª odwiedzony, • proces kontynuujemy dopóki wszystkie wierzchoªki osi¡galne z wierzchoªka ¹ródªowego w nie zostan¡ odwiedzone. Je»eli po powy»szym procesie pozostanie jakikolwiek nie odwiedzony wierzchoªek u, kontynu- ujemy przeszukiwanie traktuj¡c go jako nowy wierzchoªek ¹ródªowy. Caªy proces powtarzamy, a» wszystkie wierzchoªki w grae zostan¡ odwiedzone. Nale»y zatem zapami¦tywa¢ stany, w jakich znajduj¡ si¦ w danej chwili wierzchoªki. Do zapisania aktualnego stanu wierzchoªka u»ywamy jednego z trzech kolorów: • biaªy wszystkie wierzchoªki na pocz¡tku; szaro; • wierzchoªek odwiedzany po raz pierwszy kolorujemy na • wierzchoªek przetworzony (= lista jego s¡siadów jest caªkowicie zbadana) kolorujemy na czarno. 4 Uwaga. Tak naprawd¦ w najprostszej implementacji wystarcz¡ dwa stany: nieodwiedzony i odwiedzony. Jednak dokªadniejsze rozró»nienie stanów pozwala lepiej zrozumie¢ ide¦ DFS oraz jest wykorzystywane w niektórych zastosowaniach. DFS-Visit(G, u) 1 begin 2 kolor(u) := szary; 3 for ka»dy v 4 5 6 ∈ Adj[u] do if kolor(v) = biaªy then DFS-Visit(G, v); kolor(u) := czarny; end; Przebieg algorytmu dla u = 1 1 g w @ @ g2 w g3 w @ 4 g w 1 g w @ @ @ @ 5 @w g g2 w g6 w g3 w @ 4 g w 1 g w @ @ @ @ 5 g @w g2 w g6 w g3 w @ 4 g w 1 g w @ @ @ @ 5 g @w g2 w g6 w g3 w @ 4 g w 1 g w @ @ @ @ 5 @w g g2 w g6 w g3 w @ 4 g w @ @ 5 @w g g6 w 5 1 g w @ @ g2 w g3 w @ 4 g w 1 w g @ @ @ @ 5 @w g g2 w g6 w g3 w @ 4 g w 1 w g @ @ @ @ 5 @w g g2 w g6 w g3 w @ 4 g w 1 w g @ @ @ @ 5 g @w g2 w g6 w g3 w @ 4 g w 1 w g @ @ @ @ 5 @w g g2 w g6 w g3 w @ 4 g w 1 w g @ @ @ @ 5 g @w g2 w g6 w g3 w @ 4 g w 1 w g @ @ @ @ 5 @w g g2 w g6 w g3 w @ 4 g w @ @ 5 @w g g6 w 6 1 g w @ @ g2 w g3 w @ 4 g w 1 g w @ @ @ @ 5 @w g g2 w g6 w g3 w @ 4 g w 1 g w @ @ @ @ 5 @w g g2 w g6 w g3 w @ 4 g w 1 g w @ @ @ @ 5 g @w g2 w g6 w g3 w @ 4 g w 1 g w @ @ @ @ 5 g @w g2 w g6 w g3 w @ 4 g w 1 g w @ @ @ @ 5 g @w g2 w g6 w g3 w @ 4 g w @ @ 5 @w g Zauwa»my, »e po wywoªaniu DFS-Visit dla wierzchoªka z u g6 w u wierzchoªki, które nie s¡ osi¡galne pozostan¡ nieodwiedzone (biaªe). Aby zatem przejrze¢ caªy graf, nale»y wywoªywa¢ DFS- Visit dopóki b¦d¡ biaªe wierzchoªki. Peªen przebieg algorytmu DFS jest realizowany przez poni»sz¡ procedur¦: 7 DFS(G) 1 begin 2 for ka»dy u 3 ∈ V(G) do kolor(u) := biaªy; 4 for ka»dy u 5 ∈ V(G) do if kolor(u) = biaªy then 6 DFS-Visit(G, u); 7 end; • Zªo»ono±¢ czasowa: O(|V | + |E|): odwiedzamy ka»dy wierzchoªek i (dwukrotnie!) ka»d¡ kraw¦d¹. • Zªo»ono±¢ pami¦ciowa: O(|V |): przechowywanie kolorów, przechowywanie wierz- choªków na stosie rekurencji. 3 Zastosowania DFS 3.1 Badanie spójno±ci Podstawowe zastosowania: • Sprawdzanie spójno±ci grafu. • Wyznaczanie skªadowych spójno±ci grafu. Zauwa»my, »e w procedurze DFS wywoªujemy DFS-Visit dokªadnie tyle razy, ile jest skªadowych spójno±ci w grae G. W szczególno±ci, gdy graf jest spójny, DFS-Visit zostanie wywoªana dokªadnie raz przez procedur¦ DFS. Nietrudno uzupeªni¢ procedur¦ DFS o kod zliczaj¡cy skªadowe spójno±ci, jak równie» przypisuj¡cy wierzchoªkom numer skªadowej. 3.2 DFS - inne zastosowania Inne zastosowania: • Wyznaczanie silnie spójnych skªadowych (w wersji dla grafu skierowanego). • Sortowanie topologiczne grafu zorientowanego (bez zorientowanych cykli). • Generowanie labiryntów. • Znajdowanie drogi w labiryncie. Zainteresowanych odsyªamy do literatury (patrz te» dodatkowe materiaªy do wykªadu i zaj¦¢ laboratoryjnych). 4 BFS 4.1 Przeszukiwanie grafu wszerz Z ustalonego wierzchoªka • ¹ródªowego s przegl¡damy kolejne wierzchoªki z niego osi¡galne. wierzchoªki w odlegªo±ci (=najmniejszej liczbie kraw¦dzi) przed wierzchoªkami w odlegªo±ci k + 1, k od ¹ródªa s¡ odwiedzane 8 • granica mi¦dzy wierzchoªkami odwiedzonymi i nieodwiedzonymi jest przekraczana jednocze±nie na caªej jej szeroko±ci. Je»eli po powy»szym procesie pozostanie jakikolwiek nie odwiedzony wierzchoªek u, kontynu- ujemy przeszukiwanie traktuj¡c go jako nowy wierzchoªek ¹ródªowy. Caªy proces powtarzamy, a» wszystkie wierzchoªki w grae zostan¡ odwiedzone. Ka»dy wierzchoªek posiada jeden z 3 kolorów: biaªy, szary lub czarny (podobnie jak w DFS). Na pocz¡tku wszystkie wierzchoªki s¡ biaªe. Wierzchoªki szare s¡ przechowywane w kolejce FIFO. Po jej opuszczeniu kolorujemy je na czarno. 4.2 Kolejka FIFO Kolejka FIFO Q jest dynamiczn¡ struktur¡ danych w formie ci¡gu, do której mo»na doª¡czy¢ skªadnik tylko w jednym ko«cu (na ko«cu kolejki - head). pocz¡tku kolejki - tail), a usun¡¢ tylko w drugim ko«cu (na Mamy zatem dwie podstawowe operacje: • Enqueue(Q, v) = dodanie elementu v na ko«cu kolejki, • Dequeue(Q) = usuni¦cie elementu z pocz¡tku kolejki. Dodatkowo wykorzystamy operacj¦ • Head(Q) = zwrócenie elementu z pocz¡tku kolejki (bez usuwania go). Uwaga. Kolejk¦ implementujemy przy u»yciu struktur wska¹nikowych. Mo»na te» zasy- mulowa¢ jej dziaªanie na zwykªej (statycznej) tablicy, albo wykorzysta¢ gotowe struktury biblioteczne (np. queue biblioteki STL w C++). 4.3 Algorytm BFS-Visit(G, s) 1 begin 2 kolor(s) := szary; 3 Q := {s}; 4 while Q <> ∅ do begin 5 u := Head(Q); 6 for ka»dy v 7 8 Enqueue(Q, v) 10 end; 11 Dequeue(Q); 12 14 Adj[u] do kolor(v) := szary; 9 13 ∈ if kolor(v) = biaªy then begin kolor(u) := czarny end end Przebieg algorytmu dla s = 1 1 4 f v @ f v @ @ f2 v f3 v 5 f6 v @v f Q: 9 1 f v @ 4 f v 1 f v @ 4 f v 1 f v @ 4 f v 1 f v @ 4 f v 1 f v @ 4 f v 1 f v @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v @v f @v f @v f f @v f @v @v f @v f f @v @v f @v f @v f Q: 1 Q: 1 2 Q: 1 2 5 Q: 1 2 5 4 Q: 2 5 4 Q: 5 4 Q: 5 4 3 Q: 5 4 3 6 Q: 4 3 6 Q: 3 6 Q: 6 10 1 4 v f @ f v @ @ f2 v f3 v 5 f6 v @v f Q: Zauwa»my, »e po wywoªaniu BFS-Visit dla wierzchoªka z u u wierzchoªki, które nie s¡ osi¡galne pozostan¡ nieodwiedzone (biaªe). Aby zatem przejrze¢ caªy graf, nale»y wywoªywa¢ BFS- Visit dopóki b¦d¡ biaªe wierzchoªki. Peªen przebieg algorytmu BFS jest realizowany przez poni»sz¡ procedur¦: BFS(G) 1 begin 2 for ka»dy u 3 ∈ V(G) do kolor(u) := biaªy; 4 for ka»dy u 5 ∈ V(G) do if kolor(u) = biaªy then 6 BFS-Visit(G, u); 7 end; • Zªo»ono±¢ czasowa: O(|V | + |E|) • Zªo»ono±¢ pami¦ciowa: O(|V |) 5 (analogicznie jak dla DFS). (przechowywanie kolorów, kolejka). Zastosowania BFS 5.1 Najkrótsza droga Zastosowanie: znajdowanie najkrótszej drogi pomi¦dzy wierzchoªkami Modykacja procedury BFS-Visit: przechowywanie Tj. poprzednikiem wierzchoªka v π[v] poprzednikiem wierzchoªka Przygotowanie: for ka»dy u ∈ V(G) do begin kolor(u) := biaªy; π [u] := ∞ end; 5.2 Zmodykowany BFS BFS-Visit(G, s) 1 begin 2 kolor(s) := szary; 3 Q := {s}; 4 while Q <> ∅ do begin 5 u := Head(Q); 6 for ka»dy v 7 ∈ Adj[u] do if kolor(v) = biaªy then begin 8 kolor(v) := szary; 9 π [v] 10 end; 12 Dequeue(Q); 13 14 15 := u; Enqueue(Q, v) 11 kolor(u) := czarny end end wektora poprzedników π . na najkrótszej drodze z jest wierzchoªek s i v. π[π[v]]... s do v jest wierzchoªek π[v]; 11 Przebieg algorytmu dla s = 1 w 1 2 3 4 5 6 π[w] ∞ ∞ ∞ ∞ ∞ ∞ w 1 2 3 4 5 6 π[w] ∞ ∞ ∞ ∞ ∞ ∞ w 1 2 3 4 5 6 π[w] ∞ 1 ∞ ∞ ∞ ∞ w 1 2 3 4 5 6 π[w] ∞ 1 ∞ ∞ 1 ∞ w 1 2 3 4 5 6 π[w] ∞ 1 ∞ 1 1 ∞ w 1 2 3 4 5 6 π[w] ∞ 1 ∞ 1 1 ∞ w 1 2 3 4 5 6 π[w] ∞ 1 ∞ 1 1 ∞ w 1 2 3 4 5 6 π[w] ∞ 1 5 1 1 ∞ 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v @v f @v f f @v f @v f @v f @v @v f @v f Q: Q: 1 Q: 1 2 Q: 1 2 5 Q: 1 2 5 4 Q: 2 5 4 Q: 5 4 Q: 5 4 3 12 w 1 2 3 4 5 6 π[w] ∞ 1 5 1 1 5 w 1 2 3 4 5 6 π[w] ∞ 1 5 1 1 5 w 1 2 3 4 5 6 π[w] ∞ 1 5 1 1 5 w 1 2 3 4 5 6 π[w] ∞ 1 5 1 1 5 w 1 2 3 4 5 6 π[w] ∞ 1 5 1 1 5 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v 1 v f @ 4 f v @ @ @ @ @ @ @ @ @ @ f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v f2 v f3 v 5 f6 v @v f @v f @v f f @v f @v Q: 5 4 3 6 Q: 4 3 6 Q: 3 6 Q: 6 Q: 5.3 Odczytanie dróg π Po wykonaniu BFS-Visit(G, s) w wektorze ¹ródªowego s do wszystkich wierzchoªków w 1 w 1 2 3 4 5 6 Np. najkrótsza droga z 6 ← π[6] ← π[π[6]], 6 ← 5 ← 1. s=1 f2 v W naszym przykªadzie s = 1: f3 v @ 4 do 6 f v @ 5 @v f f6 v to: s=1 do 3 to: czyli Odczytanie i wypisanie drogi z pseudokod: v f @ s. czyli A najkrótsza droga z 3 ← π[3] ← π[π[3]], 3 ← 5 ← 1. π[w] ∞ 1 5 1 1 5 zakodowane s¡ najkrótsze drogi z wierzchoªka osi¡galnych z s do v od ko«ca mo»e by¢ zrealizowane przez poni»szy 13 PrintPathRev(s, v) 1 begin if s = v then wypisz(v) 2 π [v] 3 else if 4 else begin 5 = ∞ then wypisz('Nie ma drogi') while v <> s do begin 6 wypisz(v); 7 v := 8 π [v] end; wypisz(s) 9 10 end 11 end; Jednak bardziej naturalnym byªoby wypisanie drogi z s do v od pocz¡tku. Do tego mo»e posªu»y¢ poni»sza elegancka procedura rekurencyjna: PrintPath(s, v) 1 begin 2 if s = v then wypisz(v) 3 else if 4 else begin π [v] = ∞ 5 PrintPath(s, 6 wypisz(v) 7 then wypisz('Nie ma drogi') π [v]); end 8 end; 5.4 Podsumowanie Je»eli interesuje nas najkrótsza droga pomi¦dzy dwoma ustalonymi wierzchoªkami • uruchamiamy BFS-Visit dla wierzchoªka • odczytujemy drog¦ z Wektor π s do t z wektora s (nie tylko t!). to: s, π. b¦dzie zawieraª, jako skutek uboczny, najkrótsze drogi z choªków osi¡galnych z s i t, s do wszystkich wierz- Wyliczania tej nadmiarowej informacji nie da si¦ tu unikn¡¢. Zauwa»my, »e tu przez najkrótsz¡ drog¦ rozumieli±my drog¦ o najmniejszej liczbie kraw¦dzi. Mo»na rozwa»a¢ grafy, w których kraw¦dzie maj¡ dªugo±¢ (lub inny koszt) i poszukiwa¢ najkrótszych dróg wzgl¦dem tego parametru. Tym zagadnieniem zajmiemy si¦ na nast¦pnym wykªadzie.