Algorytmy i struktury danych
Transkrypt
Algorytmy i struktury danych
Algorytmy i struktury danych ĆWICZENIE 4 – ALGORYTM Z POWRACANIEM - (16.04.2012) Prowadząca: dr hab. inż. Małgorzata Sterna Informatyka i3, poniedziałek godz. 11:45 Adam Matuszewski, nr 106550 Oliver Kostera , nr 106552 1. Implementacja oraz testowanie. Do implementacji algorytmów posłużyliśmy się językiem C. Najpierw zaczęliśmy testować wszystkie algorytmy dla gęstości d = 0,4 od n = 6 (najmniejszy możliwy graf spójny o takiej gęstości). Przy n = 20 algorytm poszukiwania wszystkich cykli Hamiltona stał się zbyt długi i zaniechaliśmy jego testowanie kontynuując badanie czasu poszukiwania cyklu Eulera i pojedynczego cyklu Hamiltona z krokiem co 20 do n = 400. Odrębnie przetestowaliśmy algorytm wyszukiwania cyklu Eulera dla 3 różnych gęstości d = 0,2; 0,4; 0,6 zaczynając od n = 100, kończąc na n = 750. Dla tych samych gęstości również sprawdzaliśmy czasy poszukiwania pojedynczego oraz wszystkich cykli Hamiltona i liczbę wszystkich możliwych cykli Hamiltona w grafie przerywając testowanie dla danych n i poszczególnych gęstości gdy czas się stawał się zbyt długi. 2. Porównanie algorytmów poszukujących cykl Eulera i cykl Hamiltona. d = 0.4 350 300 250 czas[s] 200 150 100 50 0 7 6 9 8 11 10 13 12 15 14 17 16 19 18 40 20 80 60 120 160 200 240 280 320 360 400 100 140 180 220 260 300 340 380 n cykl Eulera Wykres.1 pojedynczy cykl Hamiltona wszystkie cykle Hamiltona d = 0,4 n tE [s] tH1 [s] tH [s] 6 0,00 0,00 0,00 7 0,00 0,00 0,00 8 0,00 0,00 0,00 9 0,00 0,00 0,00 10 0,00 0,00 0,00 11 0,00 0,00 0,00 12 0,00 0,00 0,00 13 0,00 0,00 0,00 14 0,00 0,00 0,04 15 0,00 0,00 0,16 16 0,00 0,00 0,96 17 0,00 0,00 5,55 18 0,00 0,00 59,55 19 0,00 0,00 331,58 20 0,00 0,00 ------- 40 0,00 0,00 ------- 60 0,00 0,00 ------- 80 0,00 0,00 ------- 100 0,00 0,00 ------- 120 0,00 0,00 ------- 140 0,00 13,62 ------- 160 0,00 0,00 ------- 180 0,00 0,00 ------- 200 0,00 0,00 ------- 220 0,00 0,00 ------- 240 0,00 0,00 ------- 260 0,01 0,00 ------- 280 0,01 0,01 ------- 300 0,02 0,00 ------- 320 0,02 0,04 ------- 340 0,02 0,00 ------- 360 0,03 47,00 ------- 380 0,04 0,00 ------- 400 0,05 0,00 ------- Tab.1 tE - czas poszukiwania cyklu Eulera, tH1 – czas poszukiwania pojedynczego cyklu Hamiltona, tH – czas poszukiwania wszystkich cykli Hamiltona. Wyniki testowania wszystkich algorytmów dla gęstości d = 0,4 zostały przedstawione w tabeli (Tab.1) i na wykresie (Wykres.1) powyżej. Problem znajdowania cyklu Eulera należy do klasy problemów łatwych (P – klasy problemów), czyli takich, które są rozwiązywalne przez DTM (deterministyczną maszynę Turinga) w wielomianowym czasie. Klasyfikacja ta została dokonana na podstawie tego, że istnieje algorytm, który znajduje cykl Eulera w czasie rzędu wielomianowego. Złożoność obliczeniowa tego algorytmu wyniesie O(m), jeżeli graf jest reprezentowany poprzez listę sąsiedztwa, czyli jest to algorytm wielomianowy. Problem znajdowania cyklu Hamiltona należy do klasy problemów trudnych (NP-zupełnych) czyli takich, które nie są rozwiązywalne przez DTM w czasie wielomianowym. Nie istnieje wielomianowy algorytm poszukujący cykl Hamiltona. Złożoność obliczeniowa poszukiwania pojedynczego, jak i wszystkich cykli jest wykładnicza. 3. Poszukiwanie cyklu Eulera. n d = 0,2 d = 0,4 d = 0,6 [s] [s] [s] 100 0,00 0,00 0,00 200 0,00 0,00 0,00 300 0,00 0,02 0,03 400 0,02 0,05 0,08 500 0,04 0,09 0,14 600 0,08 0,16 0,24 700 0,13 0,25 0,38 720 0,14 0,28 0,41 740 0,15 0,30 0,45 750 0,16 0,31 0,46 Tab.2 Poszukiwanie cyklu Eulera 0.5 0.45 0.4 0.35 czas [s] 0.3 0.25 0.2 0.15 0.1 0.05 0 100 200 300 400 500 600 700 720 740 n d = 0,2 d = 0,4 d = 0,6 Wykres.2 Wyniki testów algorytmu poszukiwania cyklu Eulera dla 3 różnych gęstości d = 0,2; 0,4; 0,6 zostały przedstawione powyżej w tabeli (Tab.2) i na wykresie (Wykres.2). Metoda wyszukiwania cyklu Eulera oparta jest na algorytmie przeszukiwania DFS. Z tą różnicą że analizowane są krawędzie zamiast wierzchołków. Po odwiedzeniu krawędzi, zostaje ona usunięta. Warunkiem koniecznym i dostatecznym jest spójność grafu, oraz parzysty stopień wierzchołków. W testowanych grafach istniał cykl ponieważ generowaliśmy spójne grafy o parzystych stopniach wierzchołków. Proces generowania grafu zaczynał się od generowania losowego grafu nieskierowanego o n wierzchołkach i m krawędziach, bez pętli własnych. Następnie sprawdzany był stopień kolejnych wierzchołków i gdy był on nieparzysty, tworzono (lub usuwano gdy krawędź istniała) krawędź z losowym wierzchołkiem o wyższym indeksie. W wyniku takich działań mógł powstać graf niespójny, więc w tym celu został sprawdzany metodą DFS. Gdy graf okazał się niespójny, proces tworzenia grafu został rozpoczęty od nowa. W ten sposób powstały graf był spójny, a stopień wszystkich wierzchołków był parzysty. 750 Algorytm poszukujący cyklu Eulera przechodzi co najmniej raz przez każdą z m krawędzi (czas O(m)). Przy użyciu macierzy sąsiedztwa poszukanie następnika jest O(n). Więc dla n elementów ostatecznie algorytm jest O(n2+m). Trzeba jeszcze uwzględnić czas usuwania krawędzi po przejściu przez nią, jednak w macierzy sąsiedztwa jest on symboliczny. Do reprezentowania grafu wykorzystana została macierz sąsiedztwa, która posiada dobry czas przejścia do następnego elementu. Najlepszą reprezentacją pod tym względem byłaby lista następników, jednak możliwość usuwania krawędzi zadecydowała o tym, że wybrana została macierz sąsiedztwa. Atut w postaci zajętości pamięci też nie był by aż tak widoczny, ponieważ dla jednej krawędzi musiałyby być zapamiętywane dwa następniki. Z wykresu powyżej można zauważyć, że algorytm zachowuje się naturalnie, im większa gęstość tym dłuższy czas wykonywania algorytmu, podobnie jak dla ilości wierzchołków. 4. Poszukiwanie cyklu Hamiltona n d = 0,2 d = 0,4 d = 0,6 [s] [s] [s] 20 0,00 0,00 0,00 25 1,88 0,00 0,00 30 2,36 0,00 0,00 35 0,05 0,02 0,00 40 0,00 0,00 0,00 45 0,01 0,00 0,00 50 0,00 0,00 0,00 55 0,00 0,00 0,00 60 0,00 0,01 0,00 65 0,36 0,02 0,00 Tab.3a Poszukiwanie pojedyńczego cyklu Hamiltona 2.5 czas [s] 2 1.5 1 0.5 0 20 25 30 35 40 45 50 55 60 n d = 0.2 d = 0.4 d = 0.6 Wykres.3a n d = 0,2 d = 0,4 d = 0,6 [s] [s] [s] 11 0,00 0,00 0,00 12 0,00 0,00 0,07 13 0,00 0,00 0,37 14 0,00 0,02 2,62 15 0,00 0,08 24,65 16 0,00 0,32 214,24 17 0,00 4,82 -------- 18 0,00 32,74 -------- 19 0,01 -------- -------- 20 0,35 -------- -------- Tab.3b 65 Poszukiwanie wszystkich cykli Hamiltona 250 czas [s] 200 150 100 50 0 11 12 13 14 15 16 17 18 19 n d = 0.2 d = 0.4 d = 0.6 Wykres.3b n d = 0,2 d = 0,4 d = 0,6 11 1 5 2140 12 0 2 36585 13 0 878 79571 14 1 651 881646 15 0 182 4237339 16 0 3231 48265006 17 2 57817 ------- 18 0 1443467 ------- 19 0 ------- ------- 20 0 ------- ------- Tab.4 20 Wyniki testowania czasu poszukiwania pojedynczego cyklu Hamiltona zostały przedstawione w tabeli (Tab.3a) i na wykresie (Wykres.3a) powyżej. Podobnie jak testy czasu poszukiwania wszystkich cykli Hamiltona (Tab.3b i Wykres.3b) oraz liczba cykli Hamiltona (Tab.4). Do poszukiwania cykli Hamiltona wykorzystuje się algorytm z powracaniem. Algorytm ten generuje wszystkie przypadki odrzucając te, które nie spełniają wymagań. W ten sposób może wyszukiwać pojedyncze lub wszystkie rozwiązania. Algorytm z powracaniem może być wykorzystywany również dla innych problemów niż poszukiwaniu cyklu Hamiltona, lecz często nie będzie on najszybszy. Stosuje się go dla problemów NP-zupełnych. Dla wyszukiwania jednego, jak i wszystkich cykli Hamiltona złożoność obliczeniowa algorytmu jest wykładnicza i wynosi O(n!), gdzie n! stanowi liczbę permutacji wierzchołków grafu. Algorytm z powracaniem działa szybciej niż dokonywania pełnego przeglądu wszystkich możliwych rozwiązań, gdyż błędne ścieżki zostają wykryte i odrzucone. Dla wyszukiwania pojedynczego i wszystkich cykli algorytm jest taki sam. Jednak w poszukiwaniu pojedynczego cyklu po jego znalezieniu algorytm kończy pracę, więc poszukiwanie wszystkich cykli jest pesymistycznym przypadkiem poszukiwania pojedynczego rozwiązania. Poszukiwanie wszystkich cykli jest bardziej „stabilna” od poszukiwania pojedynczego cyklu, jednak w obu przypadkach czas jest zależny od budowy grafu. Poszukiwanie pojedynczego cyklu może zakończyć się szybko gdy znajdziemy cykl na początku poszukiwań, lub wolniej gdy pod koniec. Do implementacji wykorzystana została macierz sąsiedztwa, z tych samych powodów jak wyszukiwanie cyklu Eulera. Ilość wierzchołków i krawędzi ma duży wpływ na czas działania algorytmów. Dla obu przypadków liczba wierzchołków wpływa na liczbę różnych przypadków. Im więcej wierzchołków tym większa ilość przypadków do przeanalizowania (przede wszystkim dla poszukiwania wszystkich cykli). Ilość krawędzi również ma wpływ, dla poszukiwania pojedynczego cyklu większa gęstość grafu przyspieszy znalezienie rozwiązania, ponieważ z każdego wierzchołka będziemy mieli więcej możliwości przejścia do następnego, dlatego też wraz z gęstością zwiększa się liczba cykli Hamiltona. Z drugiej strony w poszukiwaniu wszystkich cykli, mniejsza gęstość pozwoli na szybsze odrzucenie złych rozwiązań.