Transcript wyk6
Algorytmy i Struktury Danych
Grafy
WYKŁAD 6
PROWADZĄCY: DR PAWEŁ DROZDA
Plan wykładu
Podstawowe pojęcia grafowe
Reprezentacja grafów
Problemy grafowe
Algorytmy
Przeszukiwanie w głąb i wszerz
Minimalnie drzewo rozpinające
Najkrótsze ścieżki
Inne
dr Paweł Drozda
Pojęcie grafu (nieskierowany)
Nieformalnie: zbiór wierzchołków oraz krawędzi
łączących te wierzchołki
Formalnie:
Grafem (nieskierowanym) nazywamy parę G=(V,E)
V – zbiór wierzchołków
E – zbiór krawędzi, E {{u, v} : u, v V }
e2
v1
v3
e3={v2,v3}
e4
v2
dr Paweł Drozda
e1
v4
Graf skierowany
Grafem skierowanym nazywamy parę G=(V,A)
V – zbiór wierzchołków
A – zbiór krawędzi skierowanych E V V
(uporządkowanych par różnych wierzchołków)
e2
v1
v3
v4
e5
e3=(v3,v2)
e4
v2
dr Paweł Drozda
e1
Cechy grafu
Wierzchołek v i krawędź e są incydentne gdy
v e
Wierzchołki u i v są sąsiednie gdy
e {u, v} E
G’ jest podgrafem G w.t.w.
G' (V ' , E' ) G(V , E) V ' V , E' E
Stopień wierzchołka deg(v) = liczba krawędzi
incydentnych z v
dr Paweł Drozda
Cechy grafu (2)
Graf ważony to trójka G=(V,E,w), gdzie (V,E) jest
grafem, a w jest fukcją wag: w:E→R
Jeżeli
to w(e) jest wagą krawędzi e
e E
7
3
v1
v3
5
v4
1
4
v2
Wagi krawędzi:
(v1 ,v3) = 3, (v3 ,v4) = 7, (v4 ,v3) = 1
(v3 ,v2) = 4, (v2 ,v1) = 5
dr Paweł Drozda
Cechy grafu(3)
Droga to wyznaczona przez krawędzi trasa
e1 e2 ei ei+1…
pozwalająca na „podróżowanie po grafie” od wierzchołka do
wierzchołka
Ścieżka to droga nie zawierająca tych samych krawędzi. Ścieżka
wyznaczana jest przez wierzchołki
ścieżka otwarta: v1v2v3vivi+1…
ścieżka zamknięta: v1v2v3vivi+1…v1
Cykl w grafie – droga wracająca do tego samego wierzchołka
Graf cykliczny to graf w którym istnieje co najmniej jeden cykl
dr Paweł Drozda
Spójność grafu
Graf jest spójny jeżeli pomiędzy dowolnymi
jego wierzchołkami istnieje droga
e2
v1
e4
v2
e10
dr Paweł Drozda
e1
v3
e5
v7
v4
e6
e3
e9
v6
e7
e8
v5
v8
Reprezentacja grafu
Macierz sąsiedztwa – |V|2 elementów
Lista Sąsiedztwa – lepsza dla grafów rzadkich, t.j.
|E|<<|V|2, O(max(V,E))=O(V+E) elementów
e2
v1
e1
v3
e3
e4
v2
v4
1
2
3
4
1
0
1
1
0
2
1
0
1
0
3
1
1
0
1
4
0
0
1
0
1: 2→3→null
2: 1→3→null
3: 1→2→4→ null
4: 3→null
dr Paweł Drozda
Reprezentacja grafu
Macierz sąsiedztwa – |V|2 elementów
Lista Sąsiedztwa – lepsza dla grafów rzadkich, t.j.
|E|<<|V|2, O(max(V,E))=O(V+E) elementów
3
v1
5
v3
v4
1
2
3
4
1
0
2
3
0
2
2
0
1
0
3
3
1
0
5
4
0
0
5
0
1
2
1: (2,2)→(3,3)→null
v2
2: (1,2)→(3,1)→null
3: (1,3)→(2,1)→ (4,5)→ null
4: (3,5)→null
dr Paweł Drozda
Reprezentacja grafu
Dla grafu skierowanego
e2
v1
e1
v3
e3
e4
v2
v4
e5
1
2
3
4
1
1
0
1
0
2
1
0
0
0
3
0
1
0
1
4
0
0
0
0
1: 1 → 3→null
2: 1→null
3: 2→4→null
4: 3→null
dr Paweł Drozda
Problem mostów królewieckich
Czy można przejść kolejno przez wszystkie mosty tak,
żeby każdy przekroczyć tylko raz i wrócić do miejsca, z
którego się wyruszyło?
Zagadnienie opublikowane przez Eulera w 1736 roku –
pierwsza praca n.t. teorii grafów
dr Paweł Drozda
Algorytmy grafowe
Przeszukiwanie grafów
w głąb, wszerz
Drzewa – szczególna postać grafów
Znajdowanie minimalnego drzewa rozpinającego – algorytm Kruskala i
Prima
Problemy:
znajdowanie najkrótszej ścieżki (Dijkstry, Bellmana – Forda, Floyda –
Warshalla)
znajdowanie ścieżki/cyklu Eulera
chińskiego listonosza – najkrótsza droga przechodząca wszystkie
krawędzie grafu co najmniej raz
znajdowanie ścieżki/cyklu Hamiltona - Θ(n!)
komiwojażera – najkrótsza zamknięta ścieżka, przechodząca przez
wszystkie wierzchołki (minimalny cykl Hamiltona)
kojarzenia małżeństw
dr Paweł Drozda
Przeszukiwanie wszerz
Breadth-First Search
dane: graf G(V,E), wierzchołek początkowy s
BFS(G,s):
zaznacz wszystkie wierzcholki jako nieodwiedzone
enqueue(Q,s);
zaznacz s jako odwiedzony;
while ~empty(Q) do
begin
w = dequeue(Q);
foreach sasiad w do
if sasiad nie odwiedzony then
begin
zaznacz sasiad jako odwiedzony;
enqueue(Q, sasiad);
end
end
Zł. czasowa = O(|V|+|E|)
Θ(|V|) – inicjalizacja
O(|E|) – przeglądanie
dr Paweł Drozda
Przeszukiwanie w głąb
Depth-first search
dane: graf G(V,E), wierzchołek początkowy s
DFS(G,s):
zaznacz wszystkie wierzcholki jako nieodwiedzone
push(S,s);
zaznacz s jako odwiedzony;
while ~empty(S) do
begin
w = pop(Q);
foreach sasiad wierzcholka w do
if sasiad nie odwiedzony then
begin
zaznacz sasiad jako odwiedzony;
push(S, sasiad);
end
end
Zł. czasowa = O(|V|+|E|)
Θ(|V|) – inicjalizacja
O(|E|) – przeglądanie
dr Paweł Drozda
Minimalne drzewo rozpinające
Niech będzie dany graf G = <V, E> spójny niezorientowany,
skończony i niech c : E R+ będzie funkcją kosztu określoną
na krawędziach tego grafu.
Problem
Dla danego skończonego grafu G oraz danej funkcji kosztu c,
znaleźć minimalne drzewo rozpinające, tzn. takie drzewo <V, T>
rozpinające grafu G, że suma kosztów jego krawędzi eT c (e)
jest najmniejsza.
Uwaga Warunkiem koniecznym istnienia drzewa
rozpinającego grafu jest spójność!
dr Paweł Drozda
Przykład minimalne drzewo rozpinające
1
a
7
b
7
6
4
d
10
2
e
Jedno z drzew
dr Paweł Drozda
f
8
a
4
c
5
1
7
b
7
6
4
c
5
d
10
2
4
e
f
8
Minimalne drzewo
rozpinające
Algorytm Prima
Idea algorytmu
1.
Wybieramy dowolnie korzeń szukanego drzewa rozpinającego
2. W każdym kroku algorytmu wybieramy krawędź lekką – tzn.
łączącą powstałe do tej pory drzewo z jednym z pozostałych
wierzchołków najmniejszym kosztem
1
a
Krawędź lekka (c,d)
7
7
6
4
5
10
2
4
c
d
dr Paweł Drozda
b
e
f
8
Przykład - algorytm Prima
2
a
7
b
4
6
1
c
10
3
GRAF
d
2
e
5
4
f
5
g
Start – wierzchołek g:
Kolejne wierzchołki:
g-f-c-d-e-b-a
dr Paweł Drozda
a-> b, c
b -> a, c, d
c -> a, b, d, e, f
d -> b, c, e, g
e -> c, d, f
f -> c, e, g
g -> f, d
Kolejne krawędzie:
(f, g); (c, f); (c, d); (d,e);
(b, c); (a, b)
Kodowanie – algorytm Prima
Dla każdego u V
k[u] = ∞
p[u]= NIL
k[s]=0
Q=V
while Q not empty
u = EXTRACT–MIN(Q)
dla każdego v=sąsiada(u)
if v Q i w(u,v) < k[v]
then p[v] = u
k[v] = w(u,v)
dr Paweł Drozda
Algorytm Kruskala
Jeśli drzewo rozpinające ma mieć koszt minimalny i ma zawierać dany
las drzew, to musi też zawierać krawędź e, której koszt jest najmniejszy
wśród wszystkich krawędzi nie należących do żadnego z drzew i która
łączy dwa wierzchołki z różnych drzew.
• Utworzyć kolejkę priorytetową PQ z wszystkimi krawędziami
grafu, uporządkowanymi ze względu na koszt.
• Utworzyć początkowy podział Po zbioru V jako rodzinę
jednoelementowych zbiorów {x}, gdzie x V (stanowiący las
początkowy).
• Przeglądać kolejno elementy kolejki i jeżeli końce rozważanej
krawędzi należą do różnych zbiorów podziału, to krawędź
dołączyć do tworzonego drzewa, a zbiory podziału połączyć.
dr Paweł Drozda
Algorytm Kruskala – przykład
2
a
7
b
4
6
1
c
10
3
d
2
e
9
4
f
dr Paweł Drozda
8
g
Szeregowanie krawędzi
(c,d)=1
(d,e)=2
(a,b)=2
(c,f)=3
(b,c)=4
(e,f)=4
(b,d)=6
(a,c)=7
(f,g)=8
(d,g)=9
(c,e)=10
krawędzie wybrane
(c,d)=1
(d,e)=2
(a,b)=2
(c,f)=3
(b,c)=4
(e,f)=4
(b,d)=6
(a,c)=7
(f,g)=8
(d,g)=9
(c,e)=10
Kodowanie – Algorytm Kruskala
A = zbiór pusty
dla każdego v V
stwórz oddzielny zbiór
posortuj krawędzie niemalejąco względem wag
dla każdej krawędzi e według niemalejących wag
jeśli u,v należą do różnych zbiorów
A =A + {(u,v)}
połącz zbiory z u i v
dr Paweł Drozda
Wyszukiwanie najkrótszej ścieżki
Wyznaczenie najkrótszych ścieżek o wspólnym początku
Algorytm Dijkstry (zachłanny) dla grafów ważonych:
wagi są nieujemne
brak krawędzi oznaczany jest przez „odpowiednio dużą” wagę
Q – zbiór wierzchołków, do których nie jest znana optymalna
droga
D – tablica z najmniejszymi odległościami od wierzchołka do
źródła
P – tablica zawierająca nr poprzedzającego wierzchołka na
najkrótszej drodze
dr Paweł Drozda
Algorytm Dijkstry
Dijkstra(G,s):
foreach wierzchołek w
begin
d[w] = ∞;
p[w] = -1;
end
d[s] = 0;
Q = V;
while ~empty(Q) do
begin
u = wyjmij_min(Q);
foreach sasiad wierzcholka u
begin
alt = d[u]+koszt(u,sasiad);
if alt<d[sasiad] then
begin
d[sasiad] = alt;
p[sasiad] = u;
end
end
end
dr Paweł Drozda
1
10
100
30
2
50
5
60
10
3
20
4
Algorytm Bellmana – Forda
Najkrótsze ścieżki z jednego źródła
Wagi mogą być ujemne
p[] – tablica poprzedników
d[] – odległość od źródła
informuje czy da się wyznaczyć najkrótsze ścieżki –
czy nie zawiera cykli ujemnych
dr Paweł Drozda
Kodowanie – algorytm Bellmana - Forda
dla każdego v V
p[v] = nil
d[v] = ∞
for i=1 to |V| - 1
dla każdej krawędzi e(u,v) E
if d[v] > d[u] +w(u,v)
d[v] = d[u] +w(u,v)
p[v] = u
dla każdej krawędzi e(u,v) E
if d[v] > d[u] +w(u,v) RETURN FALSE
RETURN TRUE
dr Paweł Drozda
Ścieżka Eulera
Ścieżka przechodząca przez wszystkie krawędzie dokładnie raz
Graf nieskierowany
eulerowski – jeżeli wszystkie wierzchołki grafu (nieskierowanego) mają stopień
parzysty, to da się skonstruować cykl Eulera
półeulerowski – jeżeli najwyżej dwa wierzchołki mają nieparzysty stopień, to
możliwe jest zbudowanie ścieżki Eulera
Graf skierowany
eulerowski – wszystkie wierzchołki z wyjątkiem dwóch mają takie same stopnie
wychodzące i wchodzące
półeulerowski – wszystkie wierzchołki z wyjątkiem dwóch mają takie same
stopnie wychodzące i wchodzące, w jednym z tych dwóch wierzchołków stopień
wychodzący jest o 1 większy niż wchodzący a w drugim odwrotnie
dr Paweł Drozda
Algorytm
Zbadać czy graf jest spójny
Zbadać stopnie wierzchołków grafu
O(|V|+|E|)+O(|V|+|E|) = O(|V|+|E|)
Przejdź graf zaczynając od wierzchołka o
nieparzystym stopniu (jeżeli jest)
dr Paweł Drozda
Problem kojarzenia małżeństw
Graf dwudzielny – graf, w którym możemy podzielić
wierzchołki na 2 podzbiory tak, że nie istnieje krawędź
łącząca 2 wierzchołki z tego samego podzbioru
dr Paweł Drozda
Problem kojarzenia małżeństw
Problem małżeństw jest rozwiązywalny, jeśli każdy podzbiór k
panien, akceptuje jako przyszłych mężów co najmniej k
kawalerów, gdzie k ≤ n.
Filip
Anna
dr Paweł Drozda
Gustaw
Henryk
Beata
Celina
Igor
Danuta
Jan
Ewa