Algorytmy i Struktury Danych

Slides:



Advertisements
Podobne prezentacje
Tablice 1. Deklaracja tablicy
Advertisements

Algorytmy – c.d. złożoność algorytmów struktury danych
Algorytmy – c.d. struktury danych złożoność algorytmów
DOMINOWANIE W GRAFACH Magdalena Lemańska.
Grafy spełniające nierówność Γ(G) < IR(G)
Grafy o średnicy 2 i dowolnej liczbie dominowania
ALGORYTMY GRAFOWE.
Grażyna Mirkowska PJWSTK 15 listopad 2000
Wykład 10 Metody Analizy Programów Specyfikacja Struktur Danych
Grafy inaczej, czyli inne modele grafów
Homologia, Rozdział I „Przegląd” Homologia, Rozdział 1.
WYKŁAD 6. Kolorowanie krawędzi
ELEMENTY TEORII GRAFÓW
Wykład 6 Najkrótsza ścieżka w grafie z jednym źródłem
Minimalne drzewa rozpinające
Algorytm Dijkstry (przykład)
ALGORYTMY I STRUKTURY DANYCH
Elementarne struktury danych Piotr Prokopowicz
Ciągi de Bruijna generowanie, własności
-skeletony w przestrzeniach R 2 i R 3 Mirosław Kowaluk Wydział Matematyki, Informatyki i Mechaniki Uniwersytet Warszawski.
WYKŁAD 5. Skojarzenia – ciąg dalszy
WYKŁAD 2. Kolorowanie wierzchołków
WYKŁAD 7. Spójność i rozpięte drzewa
WYKŁAD 1. Grafy są wokół nas. Pojęcia wstępne.
WYKŁAD 8. Siła spójności Wierzchołek v nazywamy wierzchołkiem cięcia grafu G, gdy podgraf G-v ma więcej składowych spójności niż G. Krawędź e nazywamy.
WYKŁAD 8. Siła spójności A,B – dowolne podzbiory V(G)
WYKŁAD 3. Kliki i zbiory niezależne
GRAFY PLANARNE To grafy, które można narysować na płaszczyźnie tak, by krawędzie nie przecinały się (poza swoimi końcami). Na przykład K_4, ale nie K_5.
Dariusz Odejewski Krzysztof Wójcik
Teoretyczne podstawy informatyki
Macierz incydencji Macierzą incydencji grafu skierowanego D = (V, A), gdzie V = {1, ..., n} oraz A = {a1, ..., am}, nazywamy macierz I(D) = [aij]i=1,...,n,
Algorytmy grafowe Reprezentacja w pamięci
Hipergrafy Hipergraf jest rozszerzeniem pojęcia grafu. Hipergraf różni się od grafu nieskierowanego tym, że każda hiperkrawędź może być incydentna do dowolnej.
Komputerowa analiza sieci genowych (GRN)
ALGORYTMY I STRUKTURY DANYCH
WYKŁAD 7. Spójność i rozpięte drzewa Graf jest spójny, gdy dla każdego podziału V na dwa rozłączne podzbiory A i B istnieje krawędź z A do B. Definicja.
Minimalne drzewa rozpinające
Przepływy w sieciach. Twierdzenie minimaksowe.
O relacjach i algorytmach
Zbiór do posortowania mieści się w pamięci
SKIEROWANE Marek Bil Krzysztof Fitrzyk Krzysztof Godek.
DRZEWA BINARNE Emilia Krukowska.
Graf - jest to zbiór wierzchołków, który na rysunku przedstawiamy za pomocą kropek oraz krawędzi łączących wierzchołki. Czasami dopuszcza się krawędzie.
Algorytmy i struktury danych
Geometria obliczeniowa Wykład 3
Reprezentacja grafów i operacje na grafach na przykładzie algorytmu Dijkstry i algorytmu na odnajdywanie Silnych Spójnych Składowych Temat Opracowali:
Rodzaje, przechodzenie grafu
ALGORYTM. SCHEMATY BLOKOWE. KONSTRUKCJE PROGRAMU, PODPROGRAMY, FUNKCJE
Jerzy F. Kotowski1 Informatyka I Wykład 15 PIERWSZE KROKI.
Geometria obliczeniowa Wykład 13 Planowanie ruchu 1.Znajdywanie ścieżki między dwoma punktami. 2.Ruch postępowy robota wielokątnego na płasz- czyźnie.
PLANARNOŚĆ i KOLOROWANIE MAP. Problem Jaka jest minimalna liczba kolorów, za pomocą których można pokolorować obszary województw na mapie Polski tak,
Algorytmy i Struktury Danych Struktury Danych
Algorytmy i Struktury Danych Grafy
Drogi i cykle Eulera w grafach nieskierowanych
WĘDRÓWKI PO GRAFACH Obchody Eulera Cykle Hamiltona.
Algorytmy grafowe Minimalne drzewa rozpinające
Literatura podstawowa
GRA CHOMP. Czym jest chomp? Jest to gra dla dwóch osób, rozgrywana na prostokątnej tablicy, zwanej „tabliczką czekolady”
NP-zupełność Problemy: rozwiązywalne w czasie wielomianowym - O(nk)
Autor: Michał Salewski
Grafy.
Modelowanie matematyczne – złożoność obliczeniowa, teoria a praktyka
Pojęcia podstawowe c.d. Rachunek podziałów Elementy teorii grafów
Metody Badań Operacyjnych Michał Suchanek Katedra Ekonomiki i Funkcjonowania Przedsiębiorstw Transportowych.
Zagadnienia transportowe Katedra Ekonomiki i Funkcjonowania Przedsiębiorstw Transportowych.
Działania na grafach Autor: Anna Targońska.
Algorytm Dijkstry Podano graf Zdefiniowano jego listę sąsiedztwa 1 2 3
Macierzowe systemy kodowania konstytucji cząsteczki
Algorytmy i struktury danych
ALGORYTMY I STRUKTURY DANYCH
Zapis prezentacji:

Algorytmy i Struktury Danych Wykład 5 Grafy. Przechodzenie grafu wszerz, w głąb. Minimalne drzewo rozpinające: algorytm Kruskala i algorytm Prima.

Podstawowe definicje Grafem to struktura oznaczona jako G=(V,E) składająca się ze skończonego i niepustego zbioru wierzchołków V i zbioru krawędzi E. Krawędź od wierzchołków u do v oznaczamy jako (vi,vj). Drogą od wierzchołka v1 do vn nazywamy sekwencję krawędzi: (v1,v2), (v2,v3),…, (vn-1,vn) Dwa wierzchołki vi i vj nazywamy sąsiędnimi, jeżeli w zbiorze D istnieje krawędź (vi,vj). Taką krawędź nazywamy incydentną do wierzchołków vi, vj. Stopniem wierzchołka v deg(v) – nazywamy liczbę krawędzi do niego incydentnych. Jeśli deg(v)=0 to jest to wierzchołek izolowany. Graf rzadki = to graf, dla którego |E| jest dużo mniejsze od |V|2. Graf gęsty – to graf, dla którego |E| jest bliskie |V|2.

Oznaczenia dla złożoności Czas działania dla grafu G=(V,E) najczęściej się mierzy w zależności od liczby wierzchołków |V| i liczby krawędzi |E|. Przyjmijmy, że zapis O(|V||E|) będziemy oznaczać jako O(V E).

Rodzaje grafów: Grafy proste graf pełny – każdy wierzchołek jest połączony krawędzią z każdym wierzchołkiem

Rodzaje grafów: Grafy złożone Multigraf – dwa wierzchołki mogą być połączone kilkoma krawędziami Pseudograf – pojawiają się pętle czyli krawędzie wychodzące z i wchodzące do tego samego wierzchołka

Rodzaje grafów: Grafy złożone Graf skierowany – krawędzie, zwane też łukami, spełniają warunek (u,v)≠(v,u) 5 2 4 6 1 Graf ważony – gdy krawędziom zostają przyporządkowane liczby – wagi

Reprezentacja grafów:

Lista sąsiedztwa 1 2 3 4 5   2 3 4 1 4 1 3

Lista sąsiedztwa Niech będzie dany graf G=(V,E). Jego reprezentacja w postaci listy sąsiedztwa będzie zapisana w tablicy Adj zawierającej |V| list, gdzie każda lista odpowiadać będzie. odpowiedniemu wierzchołkowi z V. Dla każdego uV elementami listy sąsiedztwa Adj[u] są wszystkie wierzchołki v takie że krawędź (u,v) należy do zbioru E. To oznacza, że Adj[u] zawiera wszystkie wierzchołki (lub wskaźniki do nich) sąsiadujące z u w grafie G. Formę listową preferuję się dla grafów rzadkich. Formę macierzową dla gęstych lub w przypadku Jeżeli graf G będzie miał skierowane krawędzie, to suma długości wszystkich list będzie wynosić |E|, związane jest to z tym, że krawędź postaci (u,v) to wystąpienie v na liście Adj[u]. Jeżeli zaś graf G będzie miał nieskierowane krawędzie to suma długości wszystkich list wierzchołków sąsiednich będzie dana wzorem 2|E|, gdyż dla nieskierowanej krawędzi (u,v), u znajdzie się na liście sąsiadów v a v na liście sąsiadów wierzchołka u. Rozmiar wymaganej pamięci przez reprezentację listową, niezależnie czy graf jest skierowany czy nie, wynosi (V+E). Listę sąsiedztwa można wykorzystać do reprezentacji grafów ważonych. Wówczas posługujemy się funkcją wagową w:ER . Dla danego grafu ważonego G=(V,E) funkcję wagową dla krawędzi (u,v) zapiszemy jako w(u,v). W praktyce oznacza to, że wagę pamiętamy obok wierzchołka sąsiedniego.

Macierz sąsiedztwa   1 2 3 4 5 1 2 3 4 5 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 0 1 0 0 0 0 0 0 0

Macierz sąsiedztwa Niech w grafie G=(V,E) wierzchołki będą ponumerowane od 1,2, …, |V| w pewien dowolny sposób. Jeżeli mamy etykiety wierzchołków zapisane innymi znakami należy im przyporządkować numery od 1,2, …, |V|. Wówczas macierz sąsiedztwa dla grafu G będzie zapisana w postaci macierzy A=(aij) wymiaru |V|x|V| w sposób następujący: 𝑎 𝑖𝑗 = 1 𝑗𝑒ś𝑙𝑖 (𝑖,𝑗)∈𝐸 0 𝑤 𝑝𝑟𝑧𝑒𝑐𝑖𝑤𝑛𝑦𝑚 𝑝𝑟𝑧𝑦𝑝𝑎𝑑𝑘𝑢 Dla grafów nieskierowanych macierz sąsiedztwa jest symetryczna. Niech graf G=(V,E) będzie grafem ważonym z funkcją wagową w. Wówczas waga w(u,v) krawędzi (u,v)E będzie zapisana w wierszu u i kolumnie v macierzy sąsiedztwa. Jeśli dana krawędź nie istnieje to wpisujemy, NIL, 0 albo ∞, w zależności od implementacji analizowanego problemu.

Macierz incydencji (1,2) (1,3) (1,4)(3,4) 1 2 3 4 5 1 1 1 0 1 0 0 0   (1,2) (1,3) (1,4)(3,4) 1 2 3 4 5 1 1 1 0 1 0 0 0 0 1 0 1 0 0 1 1 0 0 0 0   1 2 3 4 5 1 2 3 4 5 0 -1 -1 1 0 1 0 0 0 0 1 0 0 -1-1 -1 0 1 0 0 0 0 1 0 0

Macierz incydencji Niech będzie dany graf G=(V,E). Jeżeli graf G będzie grafem skierowanym wówczas macierz incydencji zdefiniujemy jako macierz B=(bij) o wymiarze |V|x|E| taką, że 𝑏 𝑖𝑗 = −1, 𝑗𝑒ś𝑙𝑖 𝑘𝑟𝑎𝑤ę𝑑ź 𝑗 𝑤𝑦𝑐ℎ𝑜𝑑𝑧𝑖 𝑧 𝑤𝑖𝑒𝑟𝑧𝑐ℎ𝑜ł𝑘𝑎 𝑖, 1, 𝑗𝑒ś𝑙𝑖 𝑘𝑟𝑎𝑤ę𝑑ź 𝑗 𝑤𝑐ℎ𝑜𝑑𝑧𝑖 𝑑𝑜 𝑤𝑖𝑒𝑟𝑧𝑐ℎ𝑜ł𝑘𝑎 𝑖, 0 𝑤 𝑝𝑟𝑧𝑒𝑐𝑖𝑤𝑛𝑦𝑚 𝑝𝑟𝑧𝑦𝑝𝑎𝑑𝑘𝑢. Jeżeli graf G będzie grafem nieskierowanym wówczas macierz incydencji zdefiniujemy jako macierz C=(cij) o wymiarze |V|x|E| taką, że 𝑐 𝑖𝑗 = 1 𝑗𝑒ż𝑒𝑙𝑖 𝑘𝑟𝑎𝑤ę𝑑ź 𝑖,𝑗 𝑗𝑒𝑠𝑡 𝑖𝑛𝑐𝑦𝑑𝑒𝑛𝑡𝑛𝑎 𝑑𝑜 𝑤𝑖𝑒𝑟𝑧𝑐ℎ𝑜ł𝑘ó𝑤 𝑖,𝑗 0 𝑤 𝑝𝑟𝑧𝑒𝑐𝑖𝑤𝑛𝑦𝑚 𝑝𝑟𝑧𝑦𝑝𝑎𝑑𝑘𝑢.

Algorytm przechodzenia grafu Niech G(V,E), n- liczba elementów zbioru V, m – liczba elementow zbioru m, pV. Wybieramy wierzchołek startowy pV, odwiedzamy go i zaznaczamy jako odwiedzony. Odkładamy wierzchołek w wybranej strukturze danych (stos – przechodzenie w głąb, kolejka –przechodzenie wszerz). Wykonujemy dopóki struktura danych wybrana do przechowywania wierzchołków nie jest pusta odczytujemy numer wierzchołka ze struktury, Jeśli odczytany wierzchołek ma sąsiada to: odwiedzamy najbliższego jego „sąsiada” i zaznaczamy go jako odwiedzony, jeśli „sąsiad” ma wierzchołki do odwiedzenia to odkładamy go do wybranej struktury, jeśli odczytany wierzchołek nie ma sąsiada to usuwamy go ze struktury.

Przechodzenie grafu w głąb Inna nazwa dfs z ang. Depth First Search Założenia: Graf jest reprezentowany w postaci listy sąsiedztwa lstw, gdzie lstw[i][0] – liczba sąsiadów dla i-tego wierzchołka, lstw[i][k] – gdzie k=1,2,…,maxs przyjmują wartości kolejnych wierzchołków „sąsiadów”, visited[|V|] – tablica przechowująca informacje, czy wierzchołek był odwiedzony – 1 czy nie -0, current[|V|] – tablica przechowująca wskaźniki do najbliższego sąsiada danego wierzchołka. Wierzchołki grafu są przechowywane na stosie,

DFS void dfs(int n){ int startowy=1; short int visited[maxw]; if ((current[p]) <= (lstw[p][0])) { stos[0]=0; push(stos,p); while (stos[0] > 0) { v=front(stos); w=lstw[v][current[v]]; current[v]++; if (current[v]>lstw[v][0])pop(stos); if (visited[w]!=1){ wizyta(w); visited[w]=1; if ((current[w]) <= (lstw[w][0])) push(stos,w); } }} } void dfs(int n){ int startowy=1; short int visited[maxw]; int current[maxw]; int v,p,w; for (v=1;v<=n;v++) { visited[v]=0; current[v]=startowy; } p=startowy; wizyta(p); // odwiedzamy wierzchołek p visited[p]=1;// zaznaczmy p jako odwiedzony

Przechodzenie wszerz Inna nazwa bfs - Breadth-first search Założenia: Graf jest reprezentowany w postaci listy sąsiedztwa lstw, gdzie lstw[i][0] – liczba sąsiadów dla i-tego wierzchołka, lstw[i][k] – gdzie k=1,2,…,maxs przyjmują wartości kolejnych wierzchołków „sąsiadów”, visited[|V|] – tablica przechowująca informacje, czy wierzchołek był odwiedzony – 1 czy nie -0, current[|V|] – tablica przechowująca wskaźniki do najbliższego sąsiada danego wierzchołka. Wierzchołki grafu są przechowywane w kolejce,

BFS void dfs(int n){ int startowy=1; short int visited[maxw]; int current[maxw]; int v,p,w; for (v=1;v<=n;v++) { visited[v]=0; current[v]=startowy; } p=startowy; wizyta(p); // odwiedzamy wierzchołek p visited[p]=1;// zaznaczmy p jako odwiedzony if ((current[p]) <= (lstw[p][0])) { enqueue(p); while (kolejka jest nie pusta) { v=front(kolejka); w=lstw[v][current[v]]; current[v]++; if (current[v]>lstw[v][0])dequeue(); if (visited[w]!=1){ wizyta(w); visited[w]=1; if ((current[w]) <= (lstw[w][0])) enqueue(w); } }} }

Przechodzenie w głąb-Przykład

Przechodzenie wszerz - przykład

Minimalne drzewa ropinające MST- minimum spanning tree Niech graf G=(V,E) będzie spójnym grafem nieskierowanym zaś z każdą krawędzią (u,v) E jest związana waga w(u,v). Wówczas minimalnym drzewem rozpinającym będziemy nazywać drzewo T będące acyklicznym podzbiorem TE, łączącym wszystkie wierzchołki i którego łączna waga określona wzorem: 𝑤 𝑇 = (𝑢,𝑣)∈𝑇 𝑤(𝑢,𝑣) jest najmniejsza.

Rozrastanie się minimalnego drzewa rozpinającego Załóżmy, że mamy spójny graf nieskierowany G=(V,E) z funkcją wagową w:ER. Aby znaleźć minimalne drzewo rozpinające możemy użyć algorytmu zachłannego polegającego na dołączaniu pojedynczych krawędzi w poszczególnych krokach. Oznaczmy przez Z – zbiór krawędzi. Na początku każdej iteracji zbiór Z stanowi podzbiór pewnego minimalnego drzewa rozpinającego. Jest to niezmiennik pętli. W każdym kroku szukamy krawędzi (u,v) którą możemy dodać do Z tak aby Z{(u,v)} był podzbiorem minimalnego drzewa rozpinającego. Jest to krawędź bezpieczna dla Z, gdyż można ją dodać bezpiecznie do Z bez naruszenia niezmiennika.

MST - algorytm generyczny void generic_mst(graf G, waga w) { Z= while Z nie tworzy minimalnego drzewa rozpinającego znajdź krawędź (u,v), będącą bezpieczną dla Z Z=Z{(u,v)} return Z }

Podstawowe definicje Przekrój (S,V-S) grafu nieskierowanego G=(V,E) nazywamy podział V na zbiory S i V-S. Jeżeli jeden z krańców krawędzi (u,v)E należy do S, a drugi do V-S to mówimy wówczas, że krawędź ta krzyżuje się z przekrojem (S,V-S). Przekrój uwzględnia zbiór krawędzi Z, jeżeli żadna z krawędzi z Z nie krzyżuje się z tym przekrojem.

Podstawowe definicje Jeżeli krawędź krzyżuje się z przekrojem to nazywa się ją krawędzią lekką, pod warunkiem że jej waga jest najmniejsza spośród wszystkich wag krawędzi krzyżujących się z tym przekrojem. Uogólniając, krawędź będziemy nazywać krawędzią lekką o danej własności, jeżeli jej waga będzie najmniejsza spośród wag wszystkich krawędzi o danej własności.

Twierdzenie Niech będzie dany spójny graf nieskierowany G=(V,E) z funkcją wagową w:ER, Z określone jako podzbiór E zawarty w pewny minimalnym drzewie rozpinającym grafu G oraz niech (S, V-S) będzie dowolnym przekrojem G uwzględniającym Z i niech (u,v) będzie krawędzią lekką krzyżującą się z (S,V-S). Wówczas krawędź (u,v) jest bezpieczna dla Z. Wniosek Niech G=(V,E) będzie spójnym grafem nieskierowanym z funkcją wagową w o wartościach rzeczywistych, określoną na E. Niech Z będzie podzbiorem E zawartym w pewnym minimalnym drzewie rozpinającym grafu G i niech D=(VD,ED) będzie spójną składową (drzewem) w lesie Gz=(V,Z). jeśli (u,v) jest krawędzią lekką łączącą D z pewną inną składową w Gz, to krawędź (u,v) jest bezpieczna dla Z.

Algorytm Kruskala void mst_kruskal(graf G, wagi w) { A= for każdy wierzchołek vG.V MAKE_SET(v) posortuj krawędzie z G.E rosnąco względem wag w for każda krawędź (u,v)G.E, w kolejności rosnących wag {if FIND_SET(u)FIND_SET(v) Z=Z{(u,v)} UNION(u,v) } return Z

Znaczenie operacji z pseudokodu MAKE_SET(x) – tworzy nowy zbiór, którego jedynym elementem jest x i x nie może być elementem innego zbioru (warunek rozłączności zbiorów), UNION(y, z) łączy dwa zbiory dynamiczne zawierające odpowiednio y i z w nowy zbiór będący ich sumą. Zakładamy, że przed wykonaniem operacji te dwa zbiory były rozłączne. FIND_SET(x) – zwraca wskaźnik do reprezentanta (jedynego) zbioru zawierającego x.

Algorytm Kruskala - przykład

Algorytm Prima . Krawędzie ze zbioru Z tworzą tu zawsze pojedyncze drzewo. Najpierw drzewo zawiera dowolnie wybrany wierzchołek-korzeń r. Następnie w każdym kroku dodaje się do niego krawędź lekką łączącą wierzchołek z drzewa Z z izolowanym wierzchołkiem Gz=(V,Z). Wszystkie wierzchołki znajdujące się poza drzewem, ustawione są w kolejce priorytetowej Q typu min. Dla każdego wierzchołka v kluczem v.key , który ustala pozycję w kolejce, jest minimalna waga spośród wag krawędzi łączących v z wierzchołkami drzewa. Jeśli krawędzi nie ma to przyjmujemy, że v.key=∞. Natomiast atrybut v. oznacza ojca wierzchołka v w obliczanym drzewie. Podczas wykonywania algorytmu zbiór Z z procedury generic_mst jest pamiętany niejawnie jako Z={(v,v.):vV-{r}-Q} Kiedy algorytm kończy zadanie, kolejka priorytetowa Q jest pusta a minimalnym drzewem rozpinającym Z w grafie G jest: Z={(v,v.):vV-{r}}.

Algorytm Prima - pseudokod void mst_prim(graf G, wagi w, korzeń r) { for każdy uG.V u.key=∞ u.=NIL } r.key=0 Q=G.V while Q u=EXTRACT-MIN(Q) for każdy vG.adj[u] if vQ I w(u,v)<v.key v.=u v.key=w(u,v) }}}

Algorytm Prima - przykład

Bibliografia A. Drozdek, „C++. Algorytmy i struktury danych”, Helion, Gliwice 2004; L. Banachowski, K. Diks, W. Rytter, „Algorytmy i struktury danych”, WNT, Warszawa1996; Cormen Thomas; Leiserson Charles; Rivest Ronald; Stein Clifford, „Wprowadzenie do Algorytmów”, Wydawnictwo Naukowe PWN, Warszawa 2012.