Algorytmy z powrotami

Podobne dokumenty
Porządek symetryczny: right(x)

Przykładowe B+ drzewo

ZASADY PROGRAMOWANIA KOMPUTERÓW ZAP zima 2014/2015. Drzewa BST c.d., równoważenie drzew, kopce.

Poprawność semantyczna

Podstawy Programowania C++

Wykład 2. Drzewa zbalansowane AVL i 2-3-4

Algorytmy z powrotami. Algorytm minimax

Wyszukiwanie w BST Minimalny i maksymalny klucz. Wyszukiwanie w BST Minimalny klucz. Wyszukiwanie w BST - minimalny klucz Wersja rekurencyjna

Typy danych. 2. Dane liczbowe 2.1. Liczby całkowite ze znakiem i bez znaku: 32768, -165, ; 2.2. Liczby rzeczywiste stało i zmienno pozycyjne:

Jeśli czas działania algorytmu zależy nie tylko od rozmiaru danych wejściowych i przyjmuje różne wartości dla różnych danych o tym samym rozmiarze,

Wysokość drzewa Głębokość węzła

Algorytm obejścia drzewa poszukiwań i zadanie o hetmanach szachowych

. Podstawy Programowania 2. Drzewa bst - część druga. Arkadiusz Chrobot. 12 maja 2019

Strategia "dziel i zwyciężaj"

Złożoność obliczeniowa zadania, zestaw 2

Algorytmy i struktury danych. Drzewa: BST, kopce. Letnie Warsztaty Matematyczno-Informatyczne

Wstęp do programowania. Drzewa. Piotr Chrząstowski-Wachtel

Sortowanie. Bartman Jacek Algorytmy i struktury

Algorytmy i. Wykład 5: Drzewa. Dr inż. Paweł Kasprowski

Przeszukiwanie z nawrotami. Wykład 8. Przeszukiwanie z nawrotami. J. Cichoń, P. Kobylański Wstęp do Informatyki i Programowania 238 / 279

Wykład 6. Metoda eliminacji Gaussa: Eliminacja z wyborem częściowym Eliminacja z wyborem pełnym

Algorytmy i Struktury Danych

Znajdowanie wyjścia z labiryntu

Podstawy programowania Laboratorium. Ćwiczenie 2 Programowanie strukturalne podstawowe rodzaje instrukcji

Metody Kompilacji Wykład 7 Analiza Syntaktyczna

Drzewa poszukiwań binarnych

Wykład 8. Drzewa AVL i 2-3-4

Grafem nazywamy strukturę G = (V, E): V zbiór węzłów lub wierzchołków, Grafy dzielimy na grafy skierowane i nieskierowane:

Rozwiązywanie problemów metodą przeszukiwania

Analiza algorytmów zadania podstawowe

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Algorytmy i struktury danych Laboratorium 7. 2 Drzewa poszukiwań binarnych

ALGORYTMY I STRUKTURY DANYCH

Podstawy algorytmiki i programowania - wykład 6 Sortowanie- algorytmy

Podstawy programowania 2. Temat: Drzewa binarne. Przygotował: mgr inż. Tomasz Michno

Twój wynik: 4 punktów na 6 możliwych do uzyskania (66,67 %).

Metoda podziału i ograniczeń

1. Algorytmy przeszukiwania. Przeszukiwanie wszerz i w głąb.

Algorytm selekcji Hoare a. Łukasz Miemus

Podstawy Informatyki. Wykład 6. Struktury danych

liniowa - elementy następują jeden za drugim. Graficznie możemy przedstawić to tak:

Wykład 10 Grafy, algorytmy grafowe

Algorytmy i Struktury Danych

Drzewa binarne. Drzewo binarne to dowolny obiekt powstały zgodnie z regułami: jest drzewem binarnym Jeśli T 0. jest drzewem binarnym Np.

Algorytmy i str ruktury danych. Metody algorytmiczne. Bartman Jacek

dodatkowe operacje dla kopca binarnego: typu min oraz typu max:

Rozwiązanie. #include <cstdlib> #include <iostream> using namespace std;

EGZAMIN - Wersja A. ALGORYTMY I STRUKTURY DANYCH Lisek89 opracowanie kartki od Pani dr E. Koszelew

Drzewa BST i AVL. Drzewa poszukiwań binarnych (BST)

prowadzący dr ADRIAN HORZYK /~horzyk tel.: Konsultacje paw. D-13/325

Wstęp do informatyki- wykład 12 Funkcje (przekazywanie parametrów przez wartość i zmienną)

Uniwersytet Zielonogórski Wydział Elektrotechniki, Informatyki i Telekomunikacji Instytut Sterowania i Systemów Informatycznych

Pętle. Dodał Administrator niedziela, 14 marzec :27

Jak zawsze wyjdziemy od terminologii. While oznacza dopóki, podczas gdy. Pętla while jest

Metoda tabel semantycznych. Dedukcja drogi Watsonie, dedukcja... Definicja logicznej konsekwencji. Logika obliczeniowa.

Algorytmiczna teoria grafów

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

Abstrakcyjne struktury danych - stos, lista, drzewo

Zasady programowania Dokumentacja

Matematyka dyskretna - 7.Drzewa

Stos LIFO Last In First Out

Wykład 3. Złożoność i realizowalność algorytmów Elementarne struktury danych: stosy, kolejki, listy

Opis zagadnieo 1-3. Iteracja, rekurencja i ich realizacja

Definicje wyższego poziomu

Obliczenia na stosie. Wykład 9. Obliczenia na stosie. J. Cichoń, P. Kobylański Wstęp do Informatyki i Programowania 266 / 303

Definicja pliku kratowego

ALGORYTMY I STRUKTURY DANYCH

Programowanie dynamiczne cz. 2

WYKŁAD 10. Zmienne o złożonej budowie Statyczne i dynamiczne struktury danych: lista, kolejka, stos, drzewo. Programy: c5_1.c, c5_2, c5_3, c5_4, c5_5

Informatyka I. Wykład 3. Sterowanie wykonaniem programu. Instrukcje warunkowe Instrukcje pętli. Dr inż. Andrzej Czerepicki

Zadanie 1 Przygotuj algorytm programu - sortowanie przez wstawianie.

Drzewa czerwono-czarne.

Metoda Tablic Semantycznych

9.9 Algorytmy przeglądu

5.9 Modyfikacja gry Kółko i krzyżyk

Algorytmy i złożoności. Wykład 3. Listy jednokierunkowe

< K (2) = ( Adams, John ), P (2) = adres bloku 2 > < K (1) = ( Aaron, Ed ), P (1) = adres bloku 1 >

Dynamiczny przydział pamięci w języku C. Dynamiczne struktury danych. dr inż. Jarosław Forenc. Metoda 1 (wektor N M-elementowy)

4. Funkcje. Przykłady

Wykłady z Matematyki Dyskretnej

Pętla for. Wynik działania programu:

Zaawansowane algorytmy i struktury danych

Algorytmy zrandomizowane

dr inż. Paweł Myszkowski Wykład nr 11 ( )

Liczby losowe i pętla while w języku Python

Algorytmy i struktury danych. Wykład 6 Tablice rozproszone cz. 2

Programowanie obiektowe

Algorytmy i struktury danych

Języki i techniki programowania Ćwiczenia 2

Instytut Politechniczny Państwowa Wyższa Szkoła Zawodowa. Diagnostyka i niezawodność robotów

Programowanie strukturalne i obiektowe. Funkcje

Tablice mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

Algorytmy i Struktury Danych

Budowa i generowanie planszy

Wstęp do programowania

Ogólne wiadomości o grafach

Algorytmy i złożoności Wykład 5. Haszowanie (hashowanie, mieszanie)

Heurystyczne metody przeszukiwania

ALGORYTMY I STRUKTURY DANYCH

Algorytmy sortujące i wyszukujące

Wykład 6. Drzewa poszukiwań binarnych (BST)

Transkrypt:

Algorytmy z powrotami Algorytmy z powrotami są wykorzystywane do rozwiązywania problemów, w których z określonego zbioru jest wybierana sekwencja obiektów tak, aby spełniała ona określone kryteria. Klasycznym przykładem jest rozwiązanie problemu n-królowych. Zadaniem jest ustawienie n-królowych na szachownicy n n w taki sposób, aby się wzajemnie nie szachowały. Sekwencją w tym problemie jest n pozycji, na których są umieszczone królowe, zbiorem dla każdego wyboru jest n 2 możliwych pól na szachownicy. Kryterium jest takie, że królowe nie mogą się wzajemnie szachować. Algorytmy z powrotami są zmodyfikowanym przeszukiwaniem drzewa ( z korzeniem ) w głąb. Na początku odwiedzamy korzeń, a poźniej po przejściu do węzła przeglądane są wszystkie węzły potomne. Generalnie przeszukiwanie nie wymaga określonego porządku odwiedzania węzłów, ale wygodniej jest gdy przeszukiwane są węzły od lewej do prawej. Przykład przeszukiwania drzewa w głąb z węzłami ponumerowanymi w kolejności ich odwiedzania:

Węzły są ponumerowane w kolejności ich odwiedzania. Jak widać podczas wyszukiwania w głąb przechodzi się po ścieżce tak głęboko, jak jest to możliwe, aż do osiągnięcia ślepego zaułka. Następnie wracamy do węzła z niodwiedzonymi węzłami potomnymi i znów przechodzimy w głąb tak daleko, jak jest to możliwe. Rozważmy ustawienie 4 królowych na szachownicy 4 4. Problem można rozwiązać przez ustawienie królowych w kolejnych wierszach i sprawdzanie, która kombinacja kolumn daje prawidłowe rozwiązanie. Daje to 4 4 4 4 = 256 potencjalnych rozwiazań. Można tworzyć potencjalne rozwiązania przez tworzenie drzewa: w węzłach drzewa z poziomu 1 będą zapisane kolumny wybrane dla pierwszej królowej, w węzłach poziomu 2 wybrane kolumny dla drugiej królowej, etc. Ścieżka od węzła głównego do liścia jest potencjalnym rozwiazaniem. Liść to jest węzeł bez węzłów potomnych. Drzewo takie nazywamy drzewem przestrzeni stanów. Fragment drzewa przestrzeni stanów pokazano poniżej:

Całe drzewo ma 256 liści, po jednym dla każdego potencjalnego rozwiązania. W każdym węźle przechowywana jest para liczb <i,j>, oznaczająca, że królowa z wiersza i jest umieszczona w kolumnie j. Aby określić rozwiązanie, węzły są odwiedzane zgodnie z metodą przeszukiwania w głąb, w którym węzły pochodne są odwiedzane od strony lewej do prawej. Pierwsze sprawdzane scieżki to: [<1.1><2.1><3.1><4.1>] [<1.1><2.1><3.1><4.2>] [<1.1><2.1><3.1><4.3>] [<1.1><2.1><3.1><4.4>] [<1.1><2.1><3.2><4.1>] Algorytm z powrotami jest algorytmem, w którym po zorientowaniu się, że węzeł prowadzi do ślepego zaułka, wracamy do węzła nadrzędnego i kontynuujemy wyszukiwanie od następnego węzła. Węzeł nazywamy nieobiecującym, gdy w czasie jego odwiedzania można określić, że nie może on doprowadzić do rozwiązania (przykład poniżej). W przeciwnym razie węzeł jest nazywany obiecującym. Algorytm z powrotami polega na wykonywaniu przeszukiwania w głąb drzewa przestrzeni stanów, aby sprawdzić czy węzeł jest obiecujący, czy nie. Jeżeli węzeł nie jest obiecujący, wracamy do węzła nadrzędnego.

Ogólny algorytm z powrotami: void checknode (node v) { node u; if (promising(v)) if(istnieje rozwiązanie dla v) drukuj rozwiązanie; else for(każdy węzeł pochodny u węzła v) checknode(u); Algorytm z powrotami jest identyczny jak przeszukiwanie w głąb, poza tym, że węzły pochodne są odwiedzane tylko w przypadku, gdy węzeł macierzysty jest obiecujący i nie znaleziono w nim rozwiązania Dla problemu n-królowych funkcja promising zwraca false, jeżeli węzeł i dowolny z jego przodków oznaczają umieszczenie królowej w tej samej kolumnie lub przekątnej (oznaczenie x na rys.).

Algorytm z powrotami sprawdza 27 węzłów w celu odszukania rozwiązania, bez zastosowania tego algorytmu trzeba sprawdzić 155 wezłów w celu odszukania tego samego rozwiązania. Nieefektywność w ogólnym algorytmie z powrotami (procedura checknode) wynika z faktu, że sprawdzamy czy węzeł jest obiecujący, po przekazaniu go do procedury. Rekordy aktywacji wezłów nieobiecujących są niepotrzebnie odkładane na stos rekordów aktywacji. Algorytm ze sprawdzeniem czy wezeł jest obiecujący, przed wywołaniem rekurencyjnym, wyglądałby następujaco:

void expand (node v) { node u; for (każdy węzeł pochodny u węzła v) if (promising(u)) if (istnieje rozwiazanie dla u) drukuj rozwiazanie; else expand(u); Wersja poprzednia jest łatwiejsza do zrozumienia, gdyż wszystkie operacje są wykonywane w checknode tzn. : sprawdzanie czy węzeł jest obiecujący; jeżeli jest obiecujący to czy zawiera rozwiązanie; drukowanie rozwiązania. Problem n-królowych Funkcja sprawdzająca, czy węzeł jest obiecujący, musi sprawdzać, czy dwie królowe są w tej samej kolumnie lub na tej samej przekątnej. Sprawdzenie kolumny to: col(i) = col(k) gdzie col(i) jest kolumną w której jest umieszczona królowa z i-tego wiersza. Sprawdzenie przekątnej to: col(i) - col(k) = i k lub col(i) - col(k) = k i

Przykładowo: col(6) col(3) = 4-1 = 3 = 6-3 col(6) col(2) = 4-8 = -4 = 2-6 Algorytm z powrotami dla problemu n-królowych Problem: umieść n królowych na szachownicy w taki sposób, żeby żadne dwie królowe nie znalazły się w tym samym wierszu, tej samej kolumnie oraz na tych samych przekątnych. Dane wejściowe: dodatnia liczba całkowita n. Wynik: wszystkie możliwe sposoby na umieszczenie n królowych na szachownicy n n tak, aby się wzajemnie nie szachowały. Każdy wynik cząstkowy składa się z tablicy liczb całkowitych col, indeksowanych od 1 do n, gdzie col(i) jest kolumną, w której umieszczona została królowa z wiersza i.

void queens (index i) { index j; if (promising(i) ) if(i= = n) cout<< od col[i] do col[n]; else for(j=1;j<=n;j++){//sprawdzenie czy królow col[i+1] = j; //w i+1-tym wierszu moze queens(i+1); //byc ustawiona w kazdej //z n kolumn bool promising (index i) { index k; bool switch; k=1; switch = true; //Sprawdź czy jakas //krolowa szachuje królową while(k<i && switch){ //w i-tym wierszu if(col[i]==col[k] abs(col[i]-col[k])==i-k) switch = false; k++; return switch; Algorytm powyższy tworzy wszystkie rozwiązania problemu n- królowych. Przerobienie programu tak, aby zatrzymywał się po znalezieniu pierwszego rozwiazania, jest proste. W analizie algorytmu należy określić ilość sprawdzonych węzłów jako funkcję wartości n, czyli liczby królowych. Górną granicę liczby węzłów w drzewie przestrzeni stanów można dośc łatwo policzyć.

Drzewo zawiera 1 węzeł na poziomie 0, n węzłów na poziomie 1, n 2 węzłów na poziomie 2 oraz n n na poziomie n. Całkowita liczba węzłów wynosi 1+n+n 2 +n 3 + +n n = (n n+1 1) / (n 1) Przykladowo, dla n=8 mamy (8 8+1 1) / (8 1) = 19 173 961 węzłów Analiza ta jest nie w pełni użyteczna bo zadaniem algorytmu z powrotami jest uniknięcie sprawdzania wielu z tych węzłów. Można również określić górną granicę ilości węzłów obiecujących (dla n=8). Pierwsza królowa może być umieszczona w dowolnej z ośmiu kolumn, druga może być umieszczona w jednej z siedmiu kolumn. Po ustawieniu drugiej królowej dla trzeciej zostanie do wyboru sześć kolumn. Dlatego mamy co najwyżej: 1 + 8 + 8 7 + 8 7 6 + 8 7 6 5 + + 8! = 109 601 obiecujących węzłów. Ogólnie dla dowolnego n mamy co nawyżej 1 + n + n(n-1) + n(n-1)(n-2) + + n! obiecujących węzłów. Analiza ta nie jest pełna, gdyż po pierwsze nie bierze pod uwagę sprawdzania przekątnych, po drugie całkowita liczba odwiedzanych węzłów zawiera zarówno węzły obiecujące, jak i nieobiecujące. Najprostszą metodą byloby uruchomienie programu na komputerze i zliczanie odwiedzanych węzłów.

n Algorytm A Algorytm B Algorytm z powrotami Liczba węzłów Liczba potencjalnych Liczba węzłów Liczba sprawdzanych rozwiązań n! sprawdzanych znalezionych (bez powrotów) (rozne kolumny) (z powrotami) węzłów obiec. 4 341 24 61 17 8 19 173 961 40 320 15 721 2057 12 9.73 10 12 4.79 10 8 1.01 10 7 8.56 10 5 14 1.20 10 16 8.72 10 10 3.78 10 8 2.74 10 7 Oczywiście, uruchamianie algorytmu w celu określenia jego efektywności nie jest faktyczną analizą. Zadaniem analizy jest określenie jak efektywny jest algorytm, jeszcze przed jego uruchomieniem. Co można zrobić w takiej sytuacji? Algorytmy Monte-Carlo Drzewa przestrzeni stanów dla algorytmów z powrotami mają wykładniczo lub szybciej roznąca liczbę węzłów. Warto zauważyć, że jeśli mamy dwa przypadki z taką samą wartością n, jeden z nich może wymagać sprawdzenia kilku węzłów, natomiast inne wymagają sprawdzenia całego drzewa przestrzeni stanów. Jeżeli oszacujemy, jak efektywny jest dany algorytm z powrotami dla danego przypadku, możemy zdecydować, czy zastosowanie go jest sensowne. Algorytm Monte-Carlo to algorytm probabilistyczny. Jest to taki algorytm, w którym następna wykonywana instrukcja jest czasami określana w sposób losowy, zgodnie z pewnym rozkładem losowym.

Algorytm deterministyczny to taki, w którym przedstawiony przypadek nie może mieć miejsca. Algorytm Monte-Carlo pozwala oszacować spodziewaną wartość zmiennej losowej, zdefiniowanej w przestrzeni próbek, na podstawie średniej wartości losowych próbek z tej przestrzeni. Nie ma gwarancji, że to oszacowanie jest bliskie właściwej wartości oczekiwanej, ale prawdopodobieństwo, że jest bliskie, zwiększa się ze wzrostem czasu działania algorytmu (ilosci uruchomień algorytmu). Jak wykorzystać algorytm Monte-Carlo do oszacowania efektywności algorytmu z powrotami? Generujemy w drzewie typową ścieżkę, składajacą się z węzłów, które powinny być sprawdzone w danym przypadku, a nastepnie szacujemy liczbę węzłów, odgałęziających się od tej ścieżki. Oszacowanie to daje w wyniku szacunkową liczbę węzłów, które należy sprawdzić w celu znalezienia wszystkich rozwiązań. Inaczej mówiąc, jest to szacunkowa liczba węzłów w przeciętnym drzewie stanów. Muszą być spełnione dwa warunki: we wszystkich węzłach na tym samym poziomie drzewa przestrzeni stanów powinna być używana ta sama funkcja określająca, czy węzeł jest obiecujący węzły na tym samym poziomie w drzewie przestrzeni stanów muszą mieć taka samą liczbę potomków. Algorytm dla n-królowych spełnia te warunki. Technika Monte-Carlo wymaga losowego generowania obiecującego potomka węzła, zgodnie z rozkładem normalnym, czyli generowania liczb losowych. Sposób realizacji: niech m 0 będzie liczbą obiecujących potomków korzenia losowo generujemy obiecujący węzeł pochodny na poziomie 1. Niech m 1 będzie liczbą obiecujących potomków tego węzła.

losowo wygeneruj obiecujący węzeł dla węzła uzyskanego w poprzednim kroku. Niech m 2 będzie liczbą obiecujących potomków tego węzła. Losowo wygeneruj obiecujący węzeł dla węzła uzyskanego w poprzednim kroku. Niech m i będzie liczbą obiecujących potomków tego węzła. Proces jest kontynuowany, dopóki nie zostaną znalezione żadne obiecujące węzły potomne. m i jest szacunkową średnią liczbą obiecujących węzłów na poziomie i. Niech t i = całkowita liczba potomków węzła na poziomie i Wszystkie t i węzłów zostaje sprawdzone i tylko m i obiecujacych węzłów potomnych ma sprawdzone węzły potomne. Szacunkowa liczba węzłów sprawdzonych przez algorytm z powrotami w celu wyszukania wszystkich rozwiązań wynosi 1+ t 0 + m 0 t 1 + m 0 m 1 t 2 + m 0 m 1 m i-1 t i +... Ogólny algorytm obliczający tą średnią może wygladać następująco ( mprod = m 0 m 1 m i-1 ). Szacowanie Monte-Carlo Problem: oszacuj efektywność algorytmu z powrotami, korzystając z algorytmu Monte Carlo. Dane wejściowe: problem rozwiazywany przez algorytm z powrotami. Wynik: szacunkowa liczba węzłów w przyciętym drzewie przestrzeni stanów generowanych przez algorytm, który jest liczbą węzłów, jaką musi sprawdzić algorytm w celu znalezienia wszystkich rozwiązań danego przypadku.

int estimate () { node v; int m,mprod,t,numnodes; v = korzeń drzewa stanów; numnodes = 1; m=1; mprod=1; while (m!=0) { t=liczba potomków v; mprod=mprod*m; numnodes=numnodes+mprod*t; m=liczba obiecujacych potomków v; if (m!=0) v=losowo wybrany obiecujacy potomek v; return numnodes; Dla algorytmu problemu n-królowych może to wyglądać. Oszacowanie metodą Monte Carlo dla algorytmu z powrotami problem n-królowych Problem: oszacowanie efektywności algorytmu Dane wejściowe: dodatnia wartość całkowita n Wynik: szacunkowa liczba węzłów w przyciętym drzewie przestrzeni stanów, generowanym przez algorytm liczba węzłów, jakie muszą zostać sprawdzone przez algorytm przed wyszukaniem wszystkich sposobów na ustawienie n królowych na szachownicy n n tak, aby się wzajemnie nie szachowały.

int estimate_n_queens (int n) { index i,j,col[1..n]; int m,mprod,numnodes; set_of_index prom_children; i=0; numnodes=1; m=1; mprod=1; while (m!=0 && i!=n) { mprod=mprod*m; numnodes=numnodes+mprod*n;//liczba wezłów t i++; // wynosi n m=0; prom_children= ; //Inicjalizacja zbioru for(j=1;j<=n;j++){ //obiecujacych potomkow col[i]=j; //pustym zbiorem if(promising(i)){ //Okreslenie obiecuj. m++; //potomkow. prom_children=prom_children {j; if (m!=0){ j= losowy wybór z prom_children; col[i]=j; return numnodes; Algorytm Monte Carlo można uruchomić wielokrotnie i jako właściwą wartość wykorzystać średnią z otrzymanych wyników. Trzeba zauwazyć, że choć prawdopobieństwo uzyskania dobrego oszacowania jest wysokie przy wielokrotnym uruchomieniu to nigdy nie mamy gwarancji, że jest to dobre oszacowanie.

Oszacowanie uzyskiwane dla dowolnego przypadku zastosowania metody Monte Carlo jest prawdziwe tylko dla tego pojedynczego przypadku. Zdarza się, że gdy mamy dwa różne przypadki dla takiej samej wartości n, jeden może wymagać sprawdzenia niewielkiej liczby węzłów, natomiast drugi przejrzenia całego drzewa przestrzeni stanów.