V - DCC

Werbung
Kapitel 8: Graphalgorithmen
8.1
8.2
8.3
8.4
8.5
8.6
Grundlagen
Tiefen- und Breitensuche
Prim- und Kruskal-Algorithmus
Kürzeste Wege in Graphen
Eulersche und Hamiltonsche Graphen
Bipartite Graphen
1
8 Graphalgorithmen
8.1 Grundlagen
Definitionen
Gerichteter Graph (Digraph): ein geordnetes Paar
G = (V,E) ,
wobei
V = Knotenmenge (meist endliche Menge),
E = Kantenmenge, eine Teilmenge von V  V.
(Kanten haben eine Richtung!)
2
Beispiel
4
5
V = { 1, 2, 3, 4, 5 }
E = { (1,2), (2,1), (1,4), (2,4),
(4,5), (5,3), (3,5), (3,3) }
1
2
3
3
Definition (2)
w heißt Nachfolger von v und v Vorgänger von w,
wenn (v,w) aus E ist.
Loop = Kante (v,v).
4
(Ungerichteter) Graph
Kanten haben keine Richtung!
Formal: ein geordetes Paar
G = (V,E) ,
wobei
V = Knotenmenge (meist endliche Menge),
E = Kantenmenge, eine Multimenge von zweielementigen
Multimengen mit Elementen aus V ist.
(Auch Mehrfachkanten erlaubt!)
Ein Graph heißt schlicht, wenn er keine Mehrfachkanten
und keine Loops hat.
5
Beispiel
V = { 1, 2, 3, 4, 5 }
E = { (1,2), (1,4), (2,4), (4,5), (5,3)}
6
Gewichteter Graph
Gewichteter Graph oder Graph mit
Kantenbewertung: Tripel
G = (V, E, d)
mit
(V,E): Graph
d:E  {x  R | x  0} Kantenbewertung
7
Beispiel
0.5
0.18
V = { 1, 2, 3, 4, 5 }
E = { (1,2,2.5), (1,4,0.18),
(2,4,2.5), (4,5,0.5), (5,3,0.02) }
2.5
0.02
1.66
8
Eckengrad
Sei v ein Knoten in einem ungerichteten Graphen.
Eckengrad g(v) := Zahl der mit v inzidierten Kanten
= Zahl der Kanten, die ein Ende in v haben.
Handschlaglemma: Sei G ein ungerichteter Graph ohne
Loops. Dann ist {v  V} g(v)
eine gerade Zahl.
In einem gerichteten Graphen:
Eingangs- (Ausgangs-)Grad eines Knotens v := Zahl der in
v endenden (beginnenden) Kanten.
9
Erreichbarkeit und Zusammenhang in
Graphen
In einem gerichteten oder ungerichteten Graphen:
• Pfad: Knotenfolge (v0, v1, …, vp) mit (vi-1,vi) in E für i=1,…,p.
• Einfacher Pfad oder Weg: Pfad, in dem alle Knoten paarweise
verschieden sind außer evtl. dem ersten und letzten.
• Geschlossener Weg oder Kreis oder Zyklus: Weg, in dem der erste
und der letzte Knoten identisch sind.
Anmerkung bei einem ungerichteten Graphen: Gibt es mehrere Kanten zwischen
vi-1 und vi, so sollte man noch sagen, welche Kante gemeint ist.
10
Definitionen (3)
In einem ungerichteten Graphen:
• Knoten v und w sind verbunden oder w ist von v
erreichbar, wenn es einen Weg von v nach w gibt.
• Ein Teilgraph eines Graphen G=(V,E) ist ein Graph
G´=(V´,E´) mit:
V´ Teilmenge von V und E´ Teilmenge von E.
• Der Teilgraph, der aus allen von w erreichbaren Ecken
und allen zwischen diesen Ecken verlaufenden Kanten
besteht, heißt Zusammenhangskomponente von w.
• Ist dies der gesamte Graph (und das gilt dann
unabhängig von w), so heißt G zusammenhängend.
• Ein zusammenhängender Graph ohne Zykel heißt Baum.
11
Definitionen (4)
Analog in einem gerichteten Graphen:
• Zwei Knoten v und w heißen stark verbunden, wenn es
einen Weg von v nach w und einen Weg von w nach v
gibt.
• Eine stark verbundene Komponente ist ein Teilgraph
(gerichtet) mit maximaler Knotenzahl, in dem jeder
Knoten mit jedem stark verbunden ist.
12
Beispiele für Graphen:
• Verkehrsnetze mit Straßen und Kreuzungen.
• Leitungsnetze
• Einbahnverkehr oder Ströme: gerichtete
Graphen zum Zuge.
• Computer (Datenübertragugns-) netzwerke
Längen oder Kosten wie Kapazitäten von Kanten
stellen Gewichtungen, also Kantenbewertungen
dar.
13
Wichtige Fragestellungen in der Theorie der
Graphen
• Berechnung der kürzesten Entfernungen von einem
Ausgangspunkt zu allen anderen Ecken.
• Berechnung eines aufspannenden Baumes (ev. mit
minimalem Gesamtgewicht aller Kanten).
• Suchen eines Elementes in einem Graph, Feststellung
der Kreisfreiheit.
• Berechnung eines Weges, der genau alle Kanten oder
genau alle Ecken einmal durchläuft.
• Aufteilung eines Graphen in zwei elementfremde
Mengen und Untersuchung der Kanten zwischen diesen
Mengen.
• Färbungsprobleme bei Graphen.
• Eigenschaften planarer Graphen (Graphen, die auf die
Ebene gelegt werden können, ohne dass sich Kanten
überschneiden)
14
Darstellungen von gerichteten oder
ungerichteten Graphen
4
5
1.
Hier werden die Ecken jeweils an
Zeilen und Spalten angetragen und
einer Kante von der i-ten zur k-ten
Ecke entspricht eine 1 an der Stelle
(i,k) der Matrix.
1
3
2
1
1
2
3
2
3
*
5
*
*
4
5
4
*
*
*
*
*
Adjazenzmatrix:
Bei einem ungerichteten Graphen
braucht nur eine untere bzw. obere
Dreiecksmatrix notiert zu werden
und es können Doppelkanten
Berücksichtigung finden.
15
Adjazenzliste
2. Adjazenzliste:
Es werden die Nachfolger einer Ecke in eine zur
Ecke gehörige Liste eingetragen. Man erhält so
ein Listen-Array oder eine Liste von Listen.
4
5
1
2
1
2
4
2
4
1
3
3
5
4
5
5
3
3
16
Inzidenzmatrix
4
3
2
5
1
6
1
1
2
1
1
2
3
3
1
4
5
1
1
1
4
1
5
1
6
2
3. Inzidenzmatrix:
eines ungerichteten
Graphen G=(V,E): eine |V|
 |E|-Matrix I, mit i(j,k) = 0,
wenn die j-te Ecke nicht
mit der k-ten Kante
inzidiert, bzw. i(j,k)=1,2,
wenn die k-te Kante ein
bzw. zweimal (bei Loops)
mit der j-ten Ecke inzidiert.
1
1
17
Speicheraufwand
1. Adjazenzmatrix
Speicherplatz: O(|V|²)
Aufwand für die Frage: „gibt es eine Kante (v,w)?“: O(1).
2. Adjazenzliste
Speicherplatz: O(|V|+|E|)
Aufwand für die Frage: „gibt es eine Kante (v,w)?“: O(|E|).
3. Inzidenzmatrix
Speicherplatz: O(|V| • |E|)
18
8.2 Tiefen und Breitensuche
Expansion eines gerichteten Graphen von einem
Knoten v aus: der Baum X(v) mit:
• X(v) = (v), falls v keine Nachfolger hat,
• X(v) = (v, X(v1), …, X(vp)), falls v1,…,vp die
Nachfolger von v sind.
Wenn der Graph Zykel enthält, ist die Expansion
unendlich groß.
19
4
5
Beispiel Expansion
1
2
3
20
Zwei Suchalgorithmen
Tiefensuche in einem gerichteten Graphen G: PreorderDurchlauf der Expansion von G mit Abbruch jeweils bei
einem schon besuchten Knoten des Graphen: rekursiv:
Tiefensuche (v)
wenn v noch nicht besucht, dann führe aus:
Verarbeite v;
Markiere v als besucht;
für jeden Nachfolger N(v) von v (von links
nach rechts) rufe Tiefensuche (N(v)) auf.
Aufwand: O(|V| + |E|).
Datenstruktur: Stack.
21
Breitensuche
Breitensuche: durchlaufe in der Expansion
zuerst die Wurzel,
dann die Knoten auf Level 1,
sodann auf Level 2,
usw.
Aufwand: O(|V| + |E|).
Datenstruktur: Queue
22
Algorithmus Breitensuche
print(root)
Mark(root)
p = new Queue()
put all neighbors of root in q and mark them
while(!empty(q)) {
o = deletemin(q)
print(o)
put all not marked neighbors of o in q and mark them
}
•
23
Beispiel Tiefen- und Breitensuche
4
5
1
2
3
24
8.3 Prim- und Kruskal-Algorithmus
Erinnerung: Ein zusammenhängender (ungerichteter)
Graph ohne Zykel heißt Baum oder freier Baum.
Eigenschaften:
• Er besitzt bei n Knoten genau n-1 Kanten.
• Fügt man eine beliebige Kante hinzu, so enthält der aus
dem Baum entstehende Graph einen Zyklus.
• Leitungsnetze können mit freien Bäumen modelliert
werden.
Ziel: Zu einem gegebenen zusammenhängenden
gewichteten ungerichteten Graphen einen minimalen
Spannbaum berechnen (einen Baum, der Teilgraph ist,
alle Knoten enthält und minimales Gesamtgewicht hat).
25
Algorithmus von Kruskal
Beschreibung:
• Zerlege den Graphen und seine Knotenmenge in
einelementige Komponenten einer Partition P einer
Find-and-Merge-Struktur.
• Die Kanten werden in der Reihenfolge aufsteigender
Kosten betrachtet (mittels Priority-Queue Q):
Verbindet eine Kante zwei getrennte Komponenten, so
wird sie in den zu konstruierenden minimalen
Spannbaum T aufgenommen, und die beiden
Komponenten werden miteinander verschmolzen.
Anderenfalls wird die Kante ignoriert.
• Enthält P zum Schluss nur noch eine Komponente, so ist
T minimaler Spannbaum von G.
26
C
D
6
C
D
6
5
5
5
A
B
5
3
5
A
2
B
5
3
2
7
7
4
4
F
E
3
F
E
3
3
1
3
1
2
2
2
2
G
G
C
D
6
C
5
5
A
3
5
B
5
D
6
5
A
2
B
5
3
2
7
7
4
4
F
E
3
F
E
3
3
1
2
3
1
2
2
G
2
G
27
C
D
6
C
5
5
A
3
5
B
5
D
6
5
A
2
B
5
3
2
7
7
4
4
F
E
3
F
E
3
3
1
3
2
1
2
2
2
G
C
G
D
6
5
5
A
B
5
3
2
7
4
F
E
3
3
1
2
2
G
Sei G=(V,E,d) ein zusammenhängender gewichteter Graph mit n Ecken.
Es sei e := |E|.
Algorithmus Kruskal (G)
//berechnet einen minimalen Spannbaum T zum Graphen
Initialisiere die Partition P so, dass jeder Knoten aus V in einer eigenen
Komponente ist;
# O(n)
Sei T = (V, { });
Bilde eine Priority-Queue (Heap) Q aus allen Kanten
# O(e log e)
ncomp := n;
while ncomp > 1 do
# maximal e Schleifendurchläufe
(Q, (v,w)) := deletemin(Q);
# O(log e)
a:= find (P, v);
# O(log n)
b:= find (P, w);
# O(log n)
if a!=b
{insert(T,(v,w)) ; P:= merge(P,a,b); dec(ncomp); }
# O(1)
end {Kruskal}.
Partition in Find-and-Merge-Struktur: hier mit Bäumen implementiert.
Gesamtaufwand: O(e log e)
(Beachte: e >= n-1, da der Graph zusammenhängend ist).
29
Korrektheit des Algorithmus´ von Kruskal:
Zu zeigen: der konstruierte Baum T ist ein minimaler Spannbaum.
Widerspruchsbeweis.
Annahme: das ist nicht der Fall.
Sei H ein minimaler Spannbaum, der mit T die meisten Kanten
gemeinsam hat.
Sei ei die erste im Algorithmus von Kruskal betrachtete Kante, die nur in
E(T) oder nur in E(H), aber nicht in beiden Kantenmengen ist. Nach
dem Algorithmus von Kruskal ist der zweite Fall (in E(H), aber nicht
in E(T)) unmöglich. Also ist ei in E(T), aber nicht in E(H).
Fügt man ei dem Baum H hinzu, so erhält man in „H mit ei “ einen
Kreis. Auf diesem Kreis liegt eine Kante em, die nicht zu T gehört.
Nehmen wir sie heraus, so haben wir einen neuen Spannbaum H'
gefunden, der nur höchstens so großes Kantengewicht wie H hat.
Nach der Definition von ei wird nämlich ei im Algorithmus von
Kruskal eher behandelt als em, hat also höchstens so großes
Gewicht wie em. Damit ist H´ ebenfalls ein minimaler Spannbaum
und hat eine zusätzliche gemeinsame Kante mit T im Widerspruch
zur Annahme.
30
Algorithmus von Prim
Sei G=(V,E,d) ein zusammenhängender gewichteter Graph.
Ziel: Berechne einen minimalen Spannbaum T.
Kurz:
Baue den Baum T schrittweise auf: füge immer eine Kante
mit einem Ende im schon erhaltenen Baum und dem
anderen Ende außerhalb des Baums und mit minimalem
Gewicht hinzu.
Bis alle Ecken zum Baum gehören.
31
Beispiel
C
C
D
6
D
6
5
5
5
5
A
3
A
B
5
B
5
3
2
2
7
7
4
4
F
E
3
F
E
3
3
1
2
3
1
2
2
G
2
G
32
C
C
D
6
D
6
5
5
5
5
A
A
B
5
3
B
5
3
2
2
7
7
4
4
3
3
3
1
F
E
F
E
3
1
2
2
2
2
G
G
C
D
6
5
A -> B -> E
-> {G->F, D, C}
5
A
B
5
3
2
7
4
F
E
3
3
1
2
2
G
33
Algorithmus von Prim - detaillierter
Lege an:
• Eckenliste der n Ecken an, in der die zu den Ecken gehörigen Kanten mit ihren
Gewichten und die Heappositionen (s.u.) der Ecken angegeben sind,
• Kantenliste mit den inzidenten Ecken.

Initialisiere zwei Eckenmengen M = { } und N=V \ M sowie den Spannbaum T =
(V, { }).
 Man wählt nun ein y0 aus V, setzt M:={y0} und passt N an.
 Nun definiert man s(y) := d(y,y0), wobei d(y) = maxInteger gilt, falls keine Kante
von y0 zu dem Element y führt.
 Man bildet einen Heap (Größenfunktion: s(y)) aus allen Ecken aus N und
speichert die Heappositionen in der Eckenliste.
WHILE N <> { } DO BEGIN
 Sei y1 der Knoten mit minimalem s(y1). Man fügt die Kante von M nach y1
in T ein, entfernt y1 aus dem Heap und aus N und fügt y1 in M ein.
 Definiere neu s(y) := min {s(y), d(y1,y)} für alle y aus N.
 Nun muss der Heap für alle Nachbarn von y1 angepasst werden und die
Heapeigenschaft wieder hergestellt werden. Das kann mittels der
Information Heapposition jeweils mit einem Aufwand von O(log n)
geschehen.
END # While
34
Aufwand des Algorithmus von Prim:
• Erstellung der Eckenliste, der Kantenliste und des ersten Heaps.
Aufwand: O(|E| + |V| log |V|) (oder bei Verwendung der Idee aus
Heapsort zum Aufbau des ersten Heaps: O(|E| + |V|) = O(|E|) ).
• Der Update des Heaps erfordert den Durchlauf der Liste aller
Nachfolger einer Ecke und ist somit vom Aufwand O(|E| log |V|),
nämlich O(log |V|) pro Nachfolger.
• Die Heapeigenschaft wird |V|-mal nach Entnahme des Minimums
hergestellt. Aufwand: O(|V| log |V|).
Gesamtaufwand: O(|E| log|V|)
(denn |E|  |V|-1)
Anmerkung: mit einer verbesserten Heap-Datenstruktur noch schneller:
O(|E| + |V| log |V|)
(siehe [Ottmann, Widmayer: Algorithmen und Datenstrukturen]).
35
Grundlage für Algorithmus von Prim:
Beobachtung: Minimale Spannbäume enthalten eine Kante
mit Minimalgewicht.
Beweis: Wäre das nicht der Fall, so könnte man diese
Kante hinzufügen und erhielte dann einen Kreis. Zwei in
diesem Kreis benachbarte Ecken u, w können dann über
eine Kante (u,w) , aber auch noch über einen weiteren
Weg miteinander verknüpft werden. Somit kann auf
diesem Weg eine Kante gelöscht werden, ohne dass die
Baumeigenschaft verloren geht. Damit wäre ein neuer
Spannbaum erreicht, der höchstens das Gewicht des
alten, also dasselbe Gewicht wie der alte haben muss.
Somit enthielt der Ausgangsbaum bereits eine Kante
minimalen Gewichtes.
36
Diese Eigenschaft gilt sogar noch allgemeiner. Seien U und
W eine Zerlegung der Eckenmenge von G in zwei
disjunkte Teilmengen und (u,w) eine Kante mit
minimalen Kosten zwischen diesen beiden Zerlegungen.
Dann gibt es einen minimalen Spannbaum, der diese
Kante enthält.
Beweis: Auch hier könnte man (u,w) gegebenenfalls
hinzufügen und dafür eine andere Verbindung zwischen
U und W in Form einer Kante (u',w') löschen.
Die Korrektheit des Algorithmus´ von Prim zeigt man,
indem man die letzte Beobachtung in jedem
Schleifendurchlauf auf die Menge U der zum schon
konstruierten Teilbaum gehörigen Ecken und ihr
Komplement W = V \ U anwendet.
37
8.3.2 Greedy-Verfahren
Greedy-Verfahren zum Finden der Lösung eines Problems
beginnen mit der leeren Lösung und bauen diese in
jedem Schritt mit der derzeit optimal erscheinenden
Möglichkeit aus.
Der Algorithmus von Prim ist ein Greedy-Verfahren: Er
beginnt mit einer Ecke und fügt zum schon konstruierten
Baum immer eine Kante mit dem kleinsten Gewicht
hinzu (die genau ein Ende im schon konstruierten Baum
hat).
38
Herunterladen