Graphen - BFH-TI / Organisation

Werbung
Algorithmen & Datenstrukturen Lösungen
P. Fierz / HS 2012/2013
Kapitel 5
Graphen
Die Programme sind im Zipfile algorithmen.u5.zip in den Packages u5.graph und u5.util gespeichert.
In den folgenden Lösungen steht E (edges) für die Menge der Kanten und V (vertices) für
die Menge der Knoten eines Graphen. |E| (resp. |V |) bezeichnen die Anzahl Kanten (resp.
Knoten) des Graphen.
Aufgabe 5.1 [Gerichtete Graphen]
a) Es existieren die azyklischen Pfade (0,3), (0,1,2,3) und (0,1,5,2,3) also 3.
b) Es sind die Knoten 0, 1 und 4.
c) Es sind die Knoten 1, 2 und 5.
d) (1,1), (0,1,5,0), (0,1,2,3,4,5,0), (0,3,4,5,0), (0,3,4,1,5,0), (1,2,3,4,1), (1,5,2,3,4,1) und
(2,3,4,5,2).
e) Da hat es natürlich einige:
(1,1,1), . . . (1,1,1,1,1,1,1,1)
(0,1,1,5,0), . . . (0,1,1,1,1,1,5,0)
(0,1,5,0,1,5,0), (0,1,1,2,3,4,5,0)
(1,5,0,1,2,3,4,1)
usw.
f) Graphisch in der Abbildung 1-1 dargestellt. Die Tatsache dass hier für alle Knoten nur
ein Pfad entsteht ist Zufall!
5-1
Algorithmen & Datenstrukturen Lösungen
7
P. Fierz / HS 2012/2013
7
20
1
35
10
8
7
20
1
2
35
10
8
7
35
0
3
15
22
3
15
22
7
3
15
22
35
10
8
35
10
35
3
15
22
9
5
0
3
3
15
4
10
7
9
5
0
2
8
7
9
20
1
2
8
7
5
7
20
1
2
4
5
7
20
1
3
4
5
5
0
3
4
5
9
5
0
3
10
7
9
5
2
8
7
9
20
1
2
3
22
5
4
5
0
3
15
3
22
5
4
Abbildung 5-1: Kürzeste Pfade nach Dijkstra
g) Die Matrix von Floyd sieht folgendermassen aus:
|
0
1
2
3
4
5
-+----------------------------------------0| 0,-1
17,4
32,5
5,-1
8,3
24,4
1| 22,5
0,-1
15,5
25,5
28,5
7,-1
2| 44,5
22,4
0,-1 10,-1
13,3
29,4
3| 34,5
12,4
27,5
0,-1
3,-1
19,4
4| 31,5
9,-1
24,5
34,5
0,-1
16,1
5| 15,-1
30,4
8,-1
18,2
21,3
0,-1
Dabei steht die erste Zahl für die Länge des Weges (-1 = kein Pfad) und die zweite Zahl
steht für den Pivot, der zum kürzesten Weg geführt hat (-1 = kürzester Pfad ist eine
Kante).
Aufgabe 5.2 [Ungerichtete Graphen]
a) Es sind dies die folgenden Wege:
(0,3), (0,1,2,3), (0,1,5,4,3), (0,1,4,3), (0,5,4,3), (0,5,1,4,3) und (0,5,1,2,3).
b) Es existiert im Prinzip nur einen solchen Zyklus, der aber in beiden Richtungen durchlaufen werden kann. Also (0,1,2,3,4,5,0) und (0,5,4,3,2,1,0).
c) Es sind die Knoten 1, 3 und 5.
d) Die Lösung ist in der Abbildung 1-2 dargestellt.
5-2
Algorithmen & Datenstrukturen Lösungen
20
1
1
2
P. Fierz / HS 2012/2013
2
10
35
10
7
7
9
9
5
0
0
3
15
5
3
3
3
22
5
4
5
4
Abbildung 5-2: Minimal spanning tree
Aufgabe 5.3 [Graphen und Relationen]
1. Wir müssen zeigen, dass die Relation reflexiv, symetrisch und transitiv ist.
reflexiv: Da uSv gilt falls u = v ist diese Aussage trivial.
symetrisch: Falls u = v ist die Aussage trivial.
Falls u 6= v und uSv so heisst das, dass ein Zyklus existiert, der durch u und v
geht. Derselbe Zyklus geht aber natürlich auch durch v und u also glit vSu.
transitiv: Falls uSv und vSw gilt, so gibt es einen Zyklus der Form (u, (p1), v, (p2), u)
und einen Zyklus der Form (v, (p3), w, (p4), v) (dabei sind (p1) . . . (p4) Pfade im
Graph. Wir können nun den Zyklus (u, (p1), v, (p3), w, (p4), v, (p2), u) konstruieren.
Dieser Zyklus geht durch u und w also gilt auch uSw.
2. Wir müssen als erstes entscheiden, ob die Induktion über die Knoten oder über die
Kanten gemacht werden soll. Im Prinzip ist beides möglich, aber es ist über die Knoten
einfacher.
Basis: Für n = 1 stimmt die Aussage (2 · 0 = 0).
Annahme: Wir nehmen nun an, dass die Aussage für n Knoten gilt.
Induktionsschluss: Wir müssen noch zeigen, dass unter der Annahme die Aussage
auch für n + 1 Knoten und |E| Kanten gilt.
Wir entfernen als erstes den Knoten n + 1 aus dem Graph mit allen Kanten, die zu
diesem Knoten führt. Der restliche Graph hat also n Knoten und |E| − Grad(n + 1)
Kanten. Für diesen Graphen erhalten wir nach Induktionsannahme
n
X
Grad(k) = 2 · (|E| − Grad(n + 1))
k=1
Falls wir (n+1) wieder dazu nehmen, so existieren im Graphen nun Grad(n + 1)
Knoten (≤ n), deren Grad um 1 grösser wird (die Kanten, die zum Knoten n + 1
führen). Wenn wir die Summe nun bis zum Knoten n + 1 führen erhalten wir:
n+1
X
Grad(k) = 2 · (|E| − Grad(n + 1)) + Grad(n + 1) + Grad(n + 1) = 2 · |E|
k=1
5-3
Algorithmen & Datenstrukturen Lösungen
P. Fierz / HS 2012/2013
Aufgabe 5.4 [Adjazenzmatrix versus Adjazenzliste]
Adjazenzmatrix:
a) Es kann mit einem Zugriff auf das Element u, v der Matrix entschieden werden ob
die Kante existiert.
b) Wir müssen die ganze Zeile des Knotens in der Matrix lesen. Das heisst, wir
brauchen |V | Zugriffe.
c) Wir müssen die ganze Kolonne des Knotens in der Matrix lesen. Das heisst, wir
brauchen |V | Zugriffe.
d) Die Prozedur für die Tiefensuche ist nachstehend aufgeführt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
boolean arc[][] = new boolean[KMAX][KMAX];
boolean visited[] = new boolean[KMAX];
public void search() {
for (int i = 0; i < KMAX; i++)
visited[i] = false;
for (int i = 0; i < KMAX; i++) {
if (!visited[i]) {
visit(i);
}
}
}
private void visit(int k) {
visited[k] = true;
// Knoten behandeln
for (int i = 0; i < KMAX; i++) {
if (arc[k][i]) {
if (!visited[i]) {
visit(i);
}
}
}
}
Wir brauchen nicht rekursiv zu denken, da die Prozeduren so gestaltet sind, dass
die Prozedur visit genau |V | mal aufgerufen wird (für jeden Knoten einmal). Wir
müssen also nur die Komplexität von visit mal Anzahl Knoten rechnen. In visit
wird immer eine ganze Zeile der Matrix durchlaufen. Das heisst, wir brauchen
O(|V | · |V |) Operationen.
Adjazenzliste
a) Wir müssen im Durchschnitt die Hälfte der Adjazenzliste des Knotens u durchlaufen falls der Knoten v in der Liste ist, sonst die ganze Liste. Wir brauchen im
|E|
Durchschnitt also |V
| Zugriffe.
b) Wir müssen die Adjazenzliste des Knotens v durchlaufen. Im Durchschnitt brauchen
|E|
wir also |V
| Zugriffe.
5-4
Algorithmen & Datenstrukturen Lösungen
P. Fierz / HS 2012/2013
c) Wir müssen die adjazenzliste aller Knoten lesen um festzustellen, ob der Knoten
in der Liste vorkommt. Wir brauchen also ungefähr |V | + |E| Zugriffe.
d) Die Prozedur für die Tiefensuche ist nachstehend aufgeführt.
1
int adjList[][] = new int[KMAX][];
2
boolean visited[] = new boolean[KMAX];
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void search() {
for (int i = 0; i < KMAX; i++)
visited[i] = false;
for (int i = 0; i < KMAX; i++) {
if (!visited[i]) {
visit(i);
}
}
}
private void visit(int k) {
visited[k] = true;
// Knoten behandeln
for (int i = 0; i < adjList[k].length; i++) {
if (!visited[adjList[k][i]]) {
visit(adjList[k][i]);
}
}
}
Auch wenn wir einen Array von adjazenzlisten haben, können wir feststellen, dass
die Prozedur visit genau |V | mal aufgerufen wird. In der Prozedur visit werden
aber nur die effektiven Kanten die vom Knoten u ausgehen getestet. Wir nennen
diese Zahl mu . Wir können also sagen, dass dieser Loop
X
mu
u∈V
mal durchlaufen wird. Dies ist aber gerade |E|.
O(|E| + |V |)
Aufgabe 5.5 [Implementation von Graphen]
Die Aufgabe ist in den folgenden java-Files geloest:
Interfaces: Link.java und Linkable.java
Implementationen: GraphNode.java bzw. GraphLink.java
Abstracte Klassen: GeneralNet.java und Graph.java
Konkrete Graphen: DirectedGraph.java und UndirectedGraph.java
Kleine Anwendung: GraphTest.java
Aufgabe 5.6 [Tiefensuche]
In Graph.java implementiert.
Aufgabe 5.7 [Finden von Zyklen]
In DirectedGraph.java implementiert.
5-5
Algorithmen & Datenstrukturen Lösungen
P. Fierz / HS 2012/2013
Aufgabe 5.8 [Topologisches Sortieren]
In DirectedGraph.java implementiert.
Aufgabe 5.9 [Floyd]
In Graph.java implementiert.
Aufgabe 5.10 [Flussgraphen]
a) In der Figur 1-3 ist der Schnitt eingezeichnet. Wir müssen also die Summe der Kapazitäten der Vorwärtskanten bestimmen. Die Vorwärtskanten des Schnitts sind die Kanten
1 7→ 2, q 7→ s und 3 7→ 2.
c(X ) = 27
0/14
1
0/12
2
0/10
0/8
0/5
0/9
0/5
q
s
0/3
0/7
0/10
3
4
X
Abbildung 5-3: Der Schnitt X = ({q, 1, 3}, {2, 4, s})
b) In der Abbildung 1-4 ist die Lösung dargestellt. Der maximale Fluss ist |f | = 15.
c) In der Figur 1-4 ist auch ein minimaler Schnitt X = ({q, 1, 2, 3}, {4, s}) angegeben.
Aufgabe 5.11 [Flussgraph und Kapazität]
a) Offensichtlich muss die Kapazität einer Kante erhöht werden, die auf einem minimalen
Schnitt liegt. Falls eine andere Kante verändert wird, so bleibt der Flaschenhals bestehen.
Algorithmus:
(a) Finden eines minimalen Schnitts X für den Flussgraphen.
(b) Für jede Kante et auf den minimalen Schnitt:
Erhöhen der Kapazität der Kante et auf ∞ und berechnen des maximalen Flusses
fet .
(c) Bestimmen des Maximums aller gefundenen Flüsse fe′t . Die Kapazität der Kante
e′t muss vergrössert werden.
5-6
Algorithmen & Datenstrukturen Lösungen
0/14
1
0/12
0/10
0/8
0/5
0/12
0/9
0/5
2
0/10
0/8
0/5
q
0/14
1
2
P. Fierz / HS 2012/2013
0/9
5/5
q
s
s
0/3
0/3
0/7
0/7
0/10
3
0/14
1
0/12
0/10
4
3
2
1
7/10
7/8
0/5
3/12
5/5
10/10
0/9
5/5
q
s
2
7/8
0/5
0/9
q
3/14
4
s
0/3
0/3
7/7
7/7
0/10
3
0/10
4
3
4
Abbildung 5-4: Maximaler Fluss im Flussgraph N
b) Nein. Wenn im Graph zwei verschiedene minimale Schnitte existieren, die keine gemeinsame Kanten besitzen, so kann der maximale Fluss nicht vergrössert werden, indem die
Kapazität von nur einer Kante erhöht wird. In der Figur 1-5 sind die beiden Schnitte
X1 und X2 minimal (15) und haben keine gemeinsamen Kanten. Offensichtlich müssen
die Kapazität von mindestens 2 Kanten erhöht werden um den maximalen Fluss zu vergrössern.
1
5
5
q
s
1o
10
2
X
1
X
2
Abbildung 5-5: Flussgraph mit zwei minimalen Schnitten ohne gemeinsame Kante
5-7
Herunterladen