Teoria Obliczeń i Złożoności Obliczeniowej
Transkrypt
Teoria Obliczeń i Złożoności Obliczeniowej
Teoria Obliczeń i Złożoności Obliczeniowej Laboratorium: Analiza złożonosci algorytmów dla problemów NP-zupełnych. Problem komiwojażera (Travelling Salesman Problem). Zadanie komiwojażera jest koncepcyjnie bardzo proste: komiwojażer musi odwiedzić każde miasto dokładnie raz i wrócić do punktu startowego. Powinien tak zaplanować swoją trasę, znając koszt przejazdu między miastami, aby zminimalizować całkowity koszt objazdu. Optymalnym rozwiązaniem jest więc przejechanie przez wszystkie miasta jak najkrótszą drogą. Udowodniono, iż zadanie komiwojażera jest NP-trudne, czyli nie znajdziemy algorytmu szukającego optymalnego rozwiązania którego złożoność czasowa byłaby wielomianowa. Prosto napisać algorytm znajdujący optymalne rozwiązanie, ale złożoność takiego algorytmu wyklucza go w praktyce z użytku. Algorytm taki polega na kompletnym przeglądzie przestrzeni rozwiązań; ponieważ ilość możliwych dróg rośnie z ilością miast jak N!, złożoność problemu wynosi O(N!). Podobny problem pojawia się często w licznych zastosowaniach praktycznych i liczba "miast" może być całkiem znaczna, więc powyższy algorytm kompletnie nie daje się do wykorzystania. Opracowuje się więc algorytmy przybliżone, których wyniki nieznacznie "odstają" od wyników optymalnych. W praktyce nie gra dużej roli czy zadanie np. sterowania ruchem głowicy jakiejś maszyny wydłuży się o kilka sekund... Jeśli ,,zgadniemy'' sekwencję kolejnych miast, to możemy w czasie wielomianowym udowodnić, że przebyta droga spełnia warunki zadania. Jednak nie znamy deterministycznego algorytmu znajdowania rozwiązania. Stąd problemy o tych własnościach nazywamy ,,niedeterministycznie wielomianowymi'' -- nondeterministic polynomial, czyli NP. Skupiono się więc na znajdywaniu rozwiązań możliwie bliskich optymalnemu. W ciągu ostatnich kilku dziesięcioleci powstało kilka algorytmów wyznaczania rozwiązania bliskiego optymalnemu: algorytm najbliższego sąsiada, algorytm zachłanny, algorytm najbliższego wstawiania, najdalszego wstawiania, podwajanego najkrótszego drzewa rozpinającego, oddzielania powłoki wypukłej, krzywej wypełniającej przestrzeń, algorytmy Karpa, Litkego, Christofidesa itp. Zajmiemy się przetestowaniem działania kilku algorytmów używanych do poszukiwania rozwiązania problemu Komiwojażera: Heurystyka to metoda znajdowania rozwiązań dla której nie ma gwarancji znalezienia rozwiązania optymalnego, a często nawet prawidłowego. Rozwiązań tych używa się np. wtedy, gdy pełny algorytm jest z przyczyn technicznych zbyt kosztowny... tak też jest w naszym przypadku. Wśród algorytmów heurystycznych dużą role odgrywają algorytmy sukcesywnego dołączania węzłów. W każdym kroku do trasy dodawane jest nowe miasto, proces ten trwa do chwili aż trasa złożona będzie ze wszystkich miast. Istnieje wiele możliwych strategii dołączania miast np. dołączanie najdalszego miasta, dołączanie najbliższego miasta itp. Wyniki eksperymentów dla większych problemów potwierdzają, że długość rozwiązań uzyskiwanych za pomocą tej metody dołączającej najdalej położone miasto jest lepsza od pozostałych metod sukcesywnego dołączania węzłów. O dołączeniu kolejnego miasta do ścieżki decyduje tu jego odległość od najbliższego miasta w cyklu. Dołączamy to miasto, dla którego ta odległość jest największa. Raz dołączone do ścieżki częściowej miasto pozostaje w niej w kolejnych iteracjach aż do końca postępowania. Rozwiązanie uzyskane za pomocą tej metody jest zbliżone do optymalnego. Zaletą takiego postępowania jest jego niska złożoność obliczeniowa. Najbliższe miasto – drugim algorytmem jaki zbadaliśmy był algorytm dołączający do ścieżki kolejne miasta, wybierając za każdym razem to, które znajuje się najbliżej dodanego ostatnio. Algorytm charakteryzuje duża szybkość i prostota. Algorytm przegląda listę miast, oblicza odległości do każdego z nich i dołącza do ścieżki to leżące najbliżej. W każdym kolejnm kroku liczba miast które można dołączyć do ścieżki maleje o 1. Dla n miast algorytm musi więc wykonać n przebiegów, za każdym razem wybierając jedno z n-1, n-2, n-3 itd. miast. Można z tego wywnioskować, że taki algorytm będzie miał złożoność O(nlogn). Pomimo tego daje on jednak przeważnie słabe rezultaty... Algorytmy genetyczne Klasyczne algorytmy genetyczne używają łańcuchów binarnych o skończonej długości i dwóch operatorów: binarnej mutacji i binarnego krzyżowania. Program oparty o algorytm genetyczny jest algorytmem probabilistycznym, w którym generuje się populację osobników, która przekształcana jest w każdej kolejnej iteracji. Każdy osobnik przedstawia możliwe rozwiązanie rozpatrywanego zadania. W przypadku problemu Komiwojażera osobnikiem będzie struktura przedstawiająca ścieżkę łączącą wszystkie miasta. Początkowo dysponujemy pewną populacją losowo wygenerowanych osobników i w kolejnych iteracjach przez selekcję najlepszych z nich tworzy się kolejne populacje. Pewne osobniki nowej populacji podlegają dodatkowo transformacji za pomocą operatorów genetycznych, dając w ten sposób nowe rozwiązania. Po kilku krokach generacji program zbiega się i spodziewamy się, że najlepsze osobniki reprezentują rozwiązanie leżące blisko optymalnego. Reprezentacja trasy jest reprezentacją ścieżkową (kodowanie całkowitoliczbowe). Aby wyeliminować możliwość powstania osobników niedopuszczalnych w przypadku testowanego algorytmu zastosowano krzyżowanie z porządkowaniem. W tym krzyżowaniu potomków tworzy się na podstawie podtras pobranych z rodziców (podtrasa pierwszego dziecka pobierana jest z drugiego rodzica natomiast podtrasa drugiego dziecka z pierwszego). Następnie uzupełnia się trasy miastami pobranymi z drugiego rodzica z zachowaniem porządku z pominięciem miast już wykorzystanych. Jest to algorytm iteracyjny – kończy się, gdy rozwiązanie osiągnie pewną założoną dokładność. Testy Oto wyniki testów działania i efektywności powyższych algorytmów przeprowadzone dla 3 różnych konfiguracji miast. 1. (heurystyczny) 1611 (najbliższe miasto) 2078 (genetyczny) 1611 Na tym prostym przykładzie widać, że algorytm dołączający najbliższe miasto jest raczej mało efektywny. Nawet "na oko" widać, że rozwiązanie odbiega od optimum. Natomiast pozostałe 2 algorytmy dały takie same rezultaty, co utwierdza nas w przekonaniu, że udało nam się znaleźć rozwiązanie optymalne. 2. (heurystyczny) 1733 (najbliższe miasto) 1487 (genetyczny) 3023 Dla tego specyficznego przypadku najlepszy wynik dał algorytm dołączający najbliższe miasto. Miasta jednak w tym przypadku były ułożone w bardzo charakterystyczny sposób. Nieco gorzej poradził sobie z tym zadanie algorytm heurystyczny. Zawiódł natomiast algorytm genetyczny, pomimo ustawienia ilości pokoleń na 10000. Być może dobranie innych parametrów dla mutacji i krzyżowania dałoby lepszy efekt... 3. (heurystyczny) 1248 (najbliższe miasto) 1377 (genetyczny) 1268 W tym wypadku najlepszy rezultat dał algorytm heurystyczny, a niewiele gorszy – genetyczny. Po raz kolejny zawiódł algorytm dołączający najbliższe miasto... Wnioski Końcowy wniosek nasuwa się jeden: do rozwiązywania podobnych problemów należy zawsze używać kilku metod, porównać ich wyniki i wybrać najlepszą dla konkretnego przypadku. W przypadku wszystkich problemów NP-zupełnych jesteśmy skazani na algorytmy generujące rozwiązania przybliżone. Można też łączyć różne techniki np. genrując za pomocą jednego algorytmu populację startową dla algorytmu genetycznego. W wielu przypadkach algorytmy przybliżone dają na tyle satysfakcjonujące rezultaty, że można z powodzeniem wykorzystywać je do rozwiązywania rzeczywistych problemów.