Grafy Graf Graf ang graph to zbir wierzchokw

Grafy

Graf �Graf (ang. graph) to zbiór wierzchołków (ang. vertices), które mogą być połączone krawędziami (ang. edges) w taki sposób, że każda krawędź kończy się i zaczyna w którymś z wierzchołków. �Graf zapisujemy w postaci uporządkowanej pary G = (V, E), gdzie V = {v 1, v 2, …, vn} to zbiór n ponumerowanych wierzchołków a E = {e 1, e 2, …, em} to zbiór m krawędzi. �Każda krawędź jest parą wierzchołków grafu (u, v) połączonych tą krawędzią, przy czym u, v V. �Oznaczenia: |V| = n |E| = m

Przykłady grafów Graf prosty, to graf bez pętli i bez krawędzi wielokrotnych.

Historia grafów Za najstarszy przykład zastosowania grafów w rozwiązaniu zadanego problemu uznaje się zagadnienie mostów królewieckich, opis którego opublikował w 1736 roku Leonhard Euler.

Sąsiedztwo �Dwa wierzchołki u i v sąsiadują ze sobą (są sąsiednie), gdy istnieje krawędź {u, v} E. �Dwie krawędzie są incydentne, gdy mają wspólny koniec, czyli {u, v} i {v, w}. �Krawędź e jest incydentna z wierzchołkiem v, gdy v jest jednym z końców krawędzi e. �Stopień wierzchołka v to liczba wszystkich incydentnych z nim krawędzi w grafie, co oznaczamy deg(v).

Podgrafy Podgraf to fragment grafu pierwotnego. Graf G’=(V’, E’) jest podgrafem grafu G=(V, E), co zapisujemy G’ G, gdy G’ powstał z G przez usunięcie części wierzchołków wraz z incydentnymi krawędziami oraz części krawędzi, czyli V’ V oraz E’ E.

Graf gęsty �Graf gęsty to graf, w którym jest „stosunkowo dużo” krawędzi, czyli m Ω(n 2 - ), dla pewnego [0, 1). �Graf gęsty najczęściej zapisujemy w postaci macierzy sąsiedztwa. �Macierz sąsiedztwa dla grafu prostego jest symetryczna względem głównej przekątnej – można więc zredukować macierz kwadratową do macierzy trójkątnej dolnej. �Pamięć potrzebna do zaprezentowania grafu w postaci macierzy sąsiedztwa wynosi Θ(n 2).

Graf rzadki �Graf rzadki to graf, w którym jest „stosunkowo mało” krawędzi, czyli m O(n 1+ ), dla pewnego [0, 1). �Graf rzadki najczęściej zapisujemy w postaci listy sąsiadów. �Każdej krawędzi odpowiadają 2 węzły na różnych liściach sąsiadów. �Pamięć potrzebna do zaprezentowania grafu w postaci listy sąsiadów wynosi Θ(n+m).

Grafy szczególne �Graf pusty – |E|=0 �Graf pełny – |E|=(n 2 -n)/2 �Graf liniowy �Graf cykliczny �Graf kołowy �Graf dwudzielny – zbiór wierzchołków możemy podzielić na dwa rozłączne podzbiory w taki sposób, że każda krawędź ma końce należące do różnych podzbiorów, czyli V=A B, gdzie A B= , oraz każda krawędź e=(u, v) E jest postaci u A i v B.

Ścieżki i cykle �Ścieżka w grafie G o długości k, to ciąg k+1 wierzchołków (vi 0, vi 1, vi 2, …, vik) taki, że każde dwa sąsiednie wierzchołki tym ciągu są krawędzią w G, czyli (vij-1, vij) E dla j=1…k. �Ścieżka prosta w grafie G o długości k, to ścieżka, w której żadne dwa wierzchołki nie pojawiają się dwukrotnie. �Cykl w grafie G to ścieżka, w której pierwszy i ostatni wierzchołek są takie same. �Cykl prosty grafie G to cykl, w którym żaden wierzchołek, za wyjątkiem pierwszego i ostatniego, nie powtarzają się.

Spójność Graf jest spójny, gdy pomiędzy każdą parą wierzchołków istnieje jakaś ścieżka prosta, która je łączy. Każdy graf można przedstawić w postaci sumy podgrafów spójnych, które nazywają się spójnymi składowymi grafu. Wierzchołek, którego stopień wynosi 0 nazywamy wierzchołkiem izolowanym.

Spójność Minimalna liczba krawędzi w grafie spójnym wynosi n-1. Taki graf nazywa się drzewem. W drzewie nie ma cykli. Liczba krawędzi w grafie złożonym z k składowych spójności wynosi n–k ≤ m ≤ (n-k)(n-k+1)/2. Graf, który ma n wierzchołków i m > (n-1)(n-2)/2 krawędzi jest spójny.

Grafy eulerowskie Graf eulerowski to graf posiadający cykl Eulera. Cykl Eulera to cykl, który przechodzi przez wszystkie krawędzie dokładnie jeden raz. Twierdzenie: Każdy graf spójny, w którym stopnie wszystkich wierzchołków są parzyste posiada cykl Eulera. Graf jest semi-eulerowski, gdy istnieje w nim ścieżka, która przechodzi przez wszystkie krawędzie dokładnie jeden raz (grafy eulerowskie są również semi-eulerowskie).

Grafy hamiltonowskie Graf hamiltonowski to graf posiadający cykl Hamiltona. Cykl Hamiltona to cykl, który przechodzi przez wszystkie wierzchołki dokładnie jeden raz. Twierdzenie: Jeśli w grafie stopień każdego wierzchołka jest ≥n/2, gdzie n to liczba wierzchołków w grafie, to w grafie tym istnieje cykl Hamiltona. Graf jest semi-hamiltonowski, gdy istnieje w nim ścieżka, która przechodzi przez wszystkie wierzchołki dokładnie jeden raz.

Przeglądanie grafu wszerz �Zaznaczamy wszystkie wierzchołki jako nieodwiedzone. �Wyznaczamy wierzchołek startowy s i wrzucamy go do kolejki planowanych odwiedzin. �Powtarzamy następująca procedurę: wyciągamy wierzchołek z kolejki, odwiedzamy go, do kolejki odwiedzin wrzucamy wszystkich jego sąsiadów, którzy jeszcze nie byli odwiedzeni i których nie ma w kolejce.

Przeglądanie grafu wszerz Wszerz(G, s) { stwórz pustą kolejkę Q; Q. enqueue(s); while ( Q != {} ) do { x : = Q. dequeue(); przetwarzamy x; zaznacz x jako odwiedzony; for u: (x, u) E do if (u nieodwiedzony i nie ma go w kolejce) Q. enqueue(u); } }

Przeglądanie grafu w głąb �Zaznaczamy wszystkie wierzchołki jako nieodwiedzone. �Wyznaczamy wierzchołek startowy s i wrzucamy go na stos planowanych odwiedzin. �Powtarzamy następująca procedurę: ściągamy wierzchołek ze stosu, odwiedzamy go, na stos odwiedzin wrzucamy wszystkich jego sąsiadów, którzy jeszcze nie byli odwiedzeni.

Przeglądanie grafu w głąb W_glab(G, s) { stwórz pusty stos S; S. push(s); while ( S != {} ) do { x : = S. pop(); przetwarzamy x; zaznacz x jako odwiedzony; for u: (x, u) E do if (u nieodwiedzony i nie ma go na stosie) S. push(u); } }

Przeglądanie grafu Złożoność czasowa: O(n+m) bo odwiedzamy wszystkie wierzchołki i przetwarzając wierzchołek sprawdzamy wszystkich jego sąsiadów. Złożoność pamięciowa: O(n). Przeglądanie grafu w głąb można zaprogramować rekurencyjnie. Aby przeglądnąć wszystkie wierzchołki w grafie niespójnym należy iteracyjnie sprawdzać czy wierzchołek był odwiedzony, a jeśli nie to rozpoczynać ponowne przeglądanie od tego wierzchołka.

Grafy skierowane �Graf skierowany (digraf) to graf, w którym krawędzie mają kierunek (jeden wierzchołek jest początkowy a drugi końcowy). �Stopień wejściowy wierzchołka v to liczba krawędzi wchodzących do tego wierzchołka (oznaczany jako indeg(v)); stopień wyjściowy wierzchołka to liczba krawędzi wchodzących z tego wierzchołka (oznaczany jako outdeg(v)). �Silnie spójna składowa grafu skierowanego G, to taki maksymalny podgraf H (a jednocześnie jego spójna składowa), że pomiędzy każdą parą wierzchołków w H istnieją ścieżki, które je łączą.

Grafy ważone Graf ważony to graf, w którym krawędziom są przypisane pewne wagi (najczęściej nieujemne): G(V, E, w), gdzie w: E R.

Zadanie 1 Zdefiniuj graf w postaci macierzy sąsiedztwa. W grafie tym będziemy dopuszczali następujące operacje modyfikujące: dokładanie i usuwanie krawędzi. Liczba wierzchołków ma być niezmienna. Przetestuj swoją strukturę.

Zadanie 2 Napisz funkcję sprawdzającą czy zadany graf jest spójny. Wykorzystaj przeglądanie grafu wszerz.

Zadanie 3 Napisz funkcję liczącą z ilu składowych spójności składa się zadany graf. Wykorzystaj przeglądanie grafu w głąb.

Zadanie 4 Zdefiniuj graf w postaci listy sąsiadów. W grafie tym będziemy dopuszczali następujące operacje modyfikujące: dokładanie i usuwanie krawędzi. Liczba wierzchołków ma być niezmienna. Uzupełnij graf o metodę udostępniającą sąsiadów zadanego wierzchołka. Przetestuj swoją strukturę.

Algorytmy grafowe

Minimalne drzewo rozpinające (ang. minimum spaning tree) danego grafu ważonego G to taki podgraf T, który jest drzewem oraz w którym suma wag jest najmniejsza z możliwych.

Minimalne drzewo rozpinające �Algorytm Kruskala (1956 r. ): ◦ Utwórz las L z wierzchołków oryginalnego grafu – każdy wierzchołek jest na początku osobnym drzewem. ◦ Utwórz zbiór S zawierający wszystkie krawędzie oryginalnego grafu. ◦ Dopóki S nie jest pusty oraz L nie jest jeszcze drzewem rozpinającym: �Wybierz i usuń z S jedną z krawędzi o minimalnej wadze. �Jeśli krawędź ta łączyła dwa różne drzewa, to dodaj ją do lasu L, tak aby połączyła dwa odpowiadające drzewa w jedno. �W przeciwnym wypadku odrzuć ją.

Minimalne drzewo rozpinające �Implementacja algorytm Kruskala: ◦ Las L z wierzchołków oryginalnego grafu przechowujemy w strukturze dla zbiorów rozłącznych (na przykład w drzewiastej strukturze dla zbiorów rozłącznych). ◦ Zbiór S zawierający wszystkie krawędzie oryginalnego grafu przechowujemy w kolejce priorytetowej (na przykład w kopcu). ◦ Drzewo rozpinające będziemy pamiętali w postaci list sąsiadów. �Złożoność czasowa: O(E log(E)) �Złożoność pamięciowa: O(E + V)

Najkrótsze ścieżki w grafie �Najkrótsza ścieżka (ang. shortest path) w grafie ważonym to ścieżka, która łączy zadaną parę wierzchołków oraz suma wag krawędzi należących do tej ścieżki jest najmniejsza z możliwych. �Problem polega na znalezieniu w grafie ważonym najkrótszego połączenia pomiędzy danymi wierzchołkami. �Szczególnymi przypadkami tego problemu są problem najkrótszej ścieżki od jednego wierzchołka do wszystkich innych oraz problem najkrótszej ścieżki pomiędzy wszystkimi parami wierzchołków.

Najkrótsze ścieżki w grafie pomiędzy wybranym wierzchołkiem a wszystkimi pozostałymi �Algorytm Dijkstry służy do znajdowania najkrótszej ścieżki z pojedynczego źródła w grafie o nieujemnych wagach krawędzi: ◦ Przez s oznaczamy wierzchołek źródłowy. ◦ Stwórz tablicę D odległości od źródła dla wszystkich wierzchołków grafu. Na początku D[s]: =0, zaś dla wszystkich pozostałych wierzchołków D[v]: =. ◦ Utwórz kolejkę priorytetową Q wszystkich wierzchołków grafu. Priorytetem kolejki jest aktualnie wyliczona odległość od wierzchołka źródłowego s. Wstaw s do kolejki Q. ◦ Dopóki kolejka nie jest pusta: �Usuń z kolejki wierzchołek u o najniższym priorytecie (wierzchołek najbliższy źródła, który nie został jeszcze rozważony) �Dla każdego sąsiada v wierzchołka u dokonaj relaksacji poprzez u: D[v] : = min(D[u]+w(u, v), D[v]).

Najkrótsze ścieżki w grafie pomiędzy wybranym wierzchołkiem a wszystkimi pozostałymi Implementacja algorytm Dijkstry: ◦ Kolejkę priorytetową Q wszystkich wierzchołków grafu przechowujemy w kolejce priorytetowej (na przykład w kopcu). Złożoność czasowa: O(E log(V)) Złożoność pamięciowa: O(V)

Najkrótsze ścieżki w grafie pomiędzy zadaną parą wierzchołków Problem znalezienia w grafie ważonym najkrótszego połączenia pomiędzy wierzchołkiem początkowym s a wierzchołkiem docelowym t. Problem ten można rozwiązać za pomocą algorytmu Dijkstry, przerywając do w momencie rozpatrzenia wierzchołka t.

Najkrótsze ścieżki w grafie pomiędzy wszystkimi parami wierzchołków Algorytm Floyda-Warshalla służy do znajdowania najkrótszych ścieżek pomiędzy wszystkimi parami wierzchołków w grafie skierowanym ważonym o nieujemnych wagach krawędzi (wystarczy aby nie było w nim ujemnych cykli). Algorytm Floyda-Warshalla opiera się na następującym spostrzeżeniu: niech dij(k) oznacza długość najkrótszej spośród ścieżek vi do vj o wierzchołkach pośrednich w zbiorze {v 1, . . . , vk}; stąd dij(0) = Aij (połączenie przez jedną krawędź) dij(k+1) = min{dij(k), di k+1(k)+dk+1 j(k)}

Najkrótsze ścieżki w grafie pomiędzy wszystkimi parami wierzchołków skopiuj wartości macierzy sąsiedztwa T do tablicy D inicjalizuj tablicę P zerami for (każdy węzeł k grafu spośród węzłów (1, . . , n) ) for (każdy węzeł i grafu spośród węzłów (1, . . , n) ) for (każdy węzeł j grafu spośród węzłów (1, . . , n) ) if (D[i, k]+D[k, j] < D[i, j]) { D[i, j] = D[i, k] + D[k, j] //najkrótsza ścieżka prowadzi teraz przez węzeł k P[i, j] = k }

Najkrótsze ścieżki w grafie pomiędzy wszystkimi parami wierzchołków Implementacja algorytmu Floyda- Warshalla: ◦ Graf pamiętamy w macierzy. ◦ Obliczenia rozpoczynamy od macierzy odległości odwzorowującej graf pierwotny: Złożoność czasowa: O(V 3) Złożoność pamięciowa: O(V 2)

Zadanie 5 Zaprogramuj algorytm Dijkstry Znajdowania najkrótszej ścieżki w grafie z nieujemnymi wagami na krawędziach. Przetestuj swój algorytm.

Graf planarny – graf, który można narysować na płaszczyźnie (albo na kuli) tak, by krzywe obrazujące krawędzie grafu nie przecinały się ze sobą. Odwzorowanie grafu planarnego na płaszczyznę o tej własności nazywane jest jego rysunkiem płaskim. Graf planarny o zbiorze wierzchołków i krawędzi zdefiniowanym poprzez rysunek płaski nazywany jest grafem płaskim.

Graf planarny Dwa minimalne grafy, które nie są planarne, to K 5 i K 3, 3. Twierdzenie Kuratowskiego (1930) mówi, że graf skończony jest planarny wtedy i tylko wtedy, gdy nie zawiera podgrafu homeomorficznego z grafem K 5 ani z grafem K 3, 3. Dwa grafy i są homeomorficzne, jeśli można je oba otrzymać z pewnego grafu przez zastępowanie krawędzi grafu łańcuchami prostymi.

Kolorowanie grafów Kolorowanie grafu polega na przyporządkowaniu koloru każdemu węzłowi w grafie przy wykorzystaniu jak najmniejszej liczby kolorów (liczby chromatycznej), w taki sposób by dwa sąsiednie węzły nie miały tego samego koloru. Takie kolorowanie stosuje się często na mapach do oznaczenia terenów lub do określenia jak składować chemikalia bo jak wiadomo niektóre substancje po zetknięciu się ze sobą mogą spowodować eksplozje.

Kolorowanie grafów Kolorowanie grafu G=(V, E) to funkcja c: V� N taka, że c(v)≠c(w) ilekroć (vw) jest krawędzią w grafie G. Kolorowanie grafu G na k kolorów wyznacza rozbicie zbioru V na sumę rozłączną V=V 0∪V 1∪…∪Vk− 1 jednobarwnych zbiorów Vi, przy czym każdy graf indukowany postaci G|Vi jest antykliką. Na odwrót, rozbicie V=V 0∪V 1∪…∪Vk− 1 pozwala na pokolorowanie grafu G na k kolorów.

Kolorowanie grafów Graf k-kolorowalny (k-barwny) to graf dający się pokolorować k barwami. Liczba chromatyczna grafu, χ(G), to najmniejsza liczba barw, którymi można pokolorować graf G. Optymalne kolorowanie grafu G to kolorowanie używające dokładnie χ(G) kolorów. Twierdzenie: Graf, którego wszystkie wierzchołki mają stopień nie większy niż k jest (k+1)-kolorowalny.

Kolorowanie grafów Twierdzenie o czterech barwach: Dla każdego skończonego grafu planarnego istnieje funkcja, taka że każdemu z jego wierzchołków przyporządkowuje jedną z czterech liczb (barw) 1, 2, 3 i 4 w taki sposób, aby żadne sąsiednie wierzchołki nie miały przyporządkowanej tej samej liczby (barwy).
- Slides: 43