Znajdowanie wyjścia z labiryntu Zadanie to wraz z problemem pakowania najcenniejszego plecaka należy do problemów optymalizacji, które dotyczą znajdowania najlepszego rozwiązania wśród wielu możliwych rozwiązań spełniających pewne warunki. Rozwiązania powyższych zadań są jednocześnie przykładem metod heurystycznych, wykorzystujących intuicyjne sposoby otrzymania możliwie najlepszych rozwiązań - metody te są szybkie i mają duże znaczenie praktyczne. Labirynt jest zamknięty w prostokącie, ma tylko jedno wyjście/wejście i wszystkie ściany wewnętrzne są równoległe do zewnętrznych. W labiryncie nie ma zamkniętych obszarów, tzn. z każdego pola istnieje droga prowadząca do wyjścia. Pola labiryntu można ponumerować/nazwać jak na szachownicy. Naszym celem jest podanie algorytmu, który z każdego punktu labiryntu zaprowadzi nas do wyjścia, bez zbędnego kluczenia. W algorytmie takim zawsze można wyróżnić dwa elementy: - regułę gwarantującą, że żadnego odcinka drogi w labiryncie nie przechodzimy więcej niż jeden raz - strategię jak najszybszego wyjścia z labiryntu 1.Metoda po omacku (z ręką na ścianie ) Po wybraniu kierunku poruszamy się, trzymając cały czas jedną (ale tę samą ) rękę na ścianie - idziemy wzdłuż ścian. Poruszając się w ten sposób albo trafimy do wyjścia, albo wrócimy do punktu, w którym już byliśmy.
2. Metoda z powrotami W każdym punkcie (polu) labiryntu są co najwyżej cztery możliwości występowania następnego kroku: { w górę, w lewo, w prawo, w dół } - {G,L,P,D} Opis metody: 1) w polu w którym jesteśmy wybieramy z listy kierunków pierwszy, jeszcze nie zbadany kierunek przejścia z tego pola, taki że: - w tym kierunku istnieje pole nie oddzielone ścianą od "naszego" - dotychczas jeszcze nie odwiedziliśmy tego pola 2) przechodzimy na to pole
3) jeśli z danego pola nie można już przejść w żadnym kierunku, to wracamy do pola z którego przyszliśmy i kontynuujemy postępowanie Krok będący powrotem oznaczymy B, a każdy ruch możemy opisać nazwą kroku (kierunku) i nazwą pola np. G-2b, B-3a etc. Kierunek poruszania się po labiryncie określamy w zależności od naszego ustawienia i przyjmujemy, że cały czas poruszamy się "twarzą" do przodu oprócz ruchów B. Metoda z nawrotami zawsze znajduje wyjście, ale jej szybkość nie jest zadowalająca i droga wyjścia nie jest nakrótsza. Metoda ta jest przykładem przeszukiwania drzewa w głąb, gdzie w kolejnych krokach przeszukiwanie zagłębia się coraz bardziej, tak daleko jak to możliwe - teoria grafów. Metody powyższe można stosować w sytuacji, gdy znajdujemy się w labiryncie i nie znamy jego schematu, tzn. możemy korzystać tylko z lokalnych informacji, które jesteśmy w stanie zgromadzić, rozglądając się wokół siebie.
Algorytm: Metoda z powrotami - zapis rekurencyjny Problem: znaleźć wyjście z labiryntu startując z pola początkowego ν Dane: labirynt, czyli prostokąt z jednym wyjściem, wypełniony ścianami, które są równoległe do zewnętrznych ścian i nie tworzą zamkniętych obszarów. Dany jest punkt ν wewnątrz labiryntu. Wynik: Droga w labiryncie, która prowadzi z punktu ν do wyjścia. Krok 1. Dla każdego kolejnego kierunku (G,L,P,D) poruszania się z punktu ν, jeśli istnieje w tym kierunku nieodwiedzone pole w i nie jest ono odgrodzone od pola ν ścianą, to przejdź do kroku 2, a w przeciwnym razie zakończ to wywołanie algorytmu. Krok2. Jeśli wyjście z labiryntu jest w jednej ze ścian pola w, to zakończ algorytm. W przeciwnym razie oznacz pole w jako odwiedzone i wywołaj ten algorytm dla tego pola w. W zapisie tym pozornie nie ma ruchu do tyłu B. W praktyce ruch ten jest wykonywany zawsze, gdy w wyniku wywołań rekurencyjnych docieramy do miejsca, w którym nie możemy przejść do nowego pola labiryntu i przechodzimy do drugiego etapu rekurencji - powrotu z kolejnych wywołań. Znajdowanie najkrótszej drogi wyjścia z labiryntu - generowanie pól Metoda z nawrotami zawsze znajduje drogę wyjścia z labiryntu, ale nie można być zadowolonym z szybkości wykonania zadania - długo trzeba krążyć, aby trafić do wyjścia.
Należy pamiętać, że zarówno metoda po omacku, jak metoda z nawrotami może służyć do znajdowania wyjścia z labiryntu którego układ jest nieznany. Metoda generacji pól będzie działać dla labiryntu, którego schemat znamy. Metoda taka mogłaby polegać na wygenerowaniu wszystkich dróg prowadzących do wyjścia i wybraniu najkrótszej. Dróg wyjścia może być jednak bardzo dużo, choć ich liczba jest skończona, a zatem najkrótsza droga zawsze istnieje. Aby skonstruować algorytm według, którego z danego pola podążamy bezpośrednio do wyjścia, oprzemy się prostej obserwacji (zasada optymalności) - każdy fragment najkrótszej drogi między dowolnymi jej punktami jest również najkrótszą drogą między tymi punktami. Metoda znajdowania najkrótszej drogi z pola s : - generujemy pola odległe od s o jedno pole (pola przyległe) - generujemy pola odległe od s o dwa pola (które oddzielone są od s polem przyległym) - generujemy pola odległe od s o trzy pola etc., aż do osiągnięcia wyjścia {metodę tą nazywamy bliższe najpierw, wynikiem jej działania jest labirynt wypełniony liczbami} - odczytujemy od strony wyjścia pola od ległe od s o L pól, później pole odległe o L-1, następnie L-2 etc., postępujemy tak, aż do osiągnięcia pola s Aby zapisać algorytm musimy podać sposób zapamię-tywania kolejno odwiedzanych i przeglądanych pól. Zakładamy, że na początku algorytmu wszystkie pola są nieodwiedzone.
Aby mieć pewność, że pola przechodzimy w kolejności ich odległości od s, umieszczamy je w kolejności osiągania, jedno po drugim w ciągu. W tej samej kolejności opuszczają one ten ciąg, gdy przechodzimy na nowe pola, leżące o jedno pole dalej od s. Do zapamiętywania pól nadaje się tradycyjna kolejka, którą nazwiemy Q. Algorytm: Krok 0. Przyjąć, że na początku wszystkie pola są nie-odwiedzone. Krok 1. Umieścić w kolejce Q pole s. W polu s umieścić liczbę 0. Krok 2. Dopóki kolejka Q nie jest pusta, wykonywać kroki 3-5. Krok 3. Usuń z kolejki Q jej pierwszy element (pole v). Krok 4. Dla każdego pola sąsiedniego względem v i nie oddzielonego od niego ścianą wykonaj krok 5. Krok 5. Jeśli pole w nie było jeszcze odwiedzone, to umieścić w nim liczbę o jeden większą od liczby w polu v. Jeśli pole w zawiera wyjście, to przejdź do kroku 6, a w przeciwnym razie dołącz pole w na końcu kolejki Q. Krok 6. {Budujemy od końca listę pól tworzących najkrótszą drogę z pola s do pola w na którym zakończył działanie krok 5. } Dopóki w nie jest polem s : za kolejne (od końca ) pole drogi przyjąć w i za nową wartość w przyjąć pole sąsiednie względem w, w którym znajduje się liczba o jeden mniejsza od liczby znajdującej się w obecnym polu w.
Algorytm ten jest szczególnym przypadkiem algorytmu Dijkstry (problem komiwojażera) wyznaczania najkrótszej drogi w dowolnej sieci połączeń, w której odległości między punktami są nieujemne.