3.6 Branch-and-Bound

Werbung
3.6
Branch-and-Bound-Verfahren
Die Branch-and-Bound“-Methode beruht darauf, auf eine intelligente“ Weise alle zulässigen
”
”
Lösungen eines kombinatorischen Optimierungsproblems aufzulisten und mit Hilfe von bekannten Schranken Lösungen dabei auszuschließen, die als Optimum nicht in Frage kommen können.
Wir wollen dies an Hand einiger bekannter Probleme deutlich machen und betrachten zuerst
das ganzzahlige Lineare Optimierungsproblem
min z = c0 x = c(x);
Ax ≤ b;
x ≥ 0;
x ganzzahlig.
Läßt man die Forderung der Ganzzahligkeit der Lösung außer acht, dann erhält man eine
Lösung x0 des LP, die i.a. nicht ganzzahlig ist. Die Kosten c(x0 ) sind sicher auch eine untere
Schranke für die Kosten einer optimalen Lösung x∗ des ILP. Wenn x0 schon ganzzahlig ist,
hat man eine gesuchte Lösung des ILP. Im anderen Fall gibt es mindestens eine Komponente
x0i , die nicht ganzzahlig ist. Wir könnten nun unser Ausgangsproblem aufspalten in die beiden
Teilprobleme
Problem 1:
min z = c0 x = c(x);
Ax ≤ b;
x ≥ 0;
x ganzzahlig;
xi ≤ [x0i ]
min z = c0 x = c(x);
Ax ≤ b;
x ≥ 0;
x ganzzahlig;
xi ≥ [x0i ] + 1.
und
Problem 2:
Beispiel 3.6.1 Wir wollen die Vorgehensweise an dem Beispiel mit


 1
−2 1
−2
c(x) := −(x1 + x2 ); A =  0 −1 ; b = − 12 
11
2
1
2
verdeutlichen.
x2
6
c(x) = −(x1 + x2 )
...
..... ........... ..
.. . .....
....
..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
...c
..
. ..
. ..... .. .. .. .. .. ..... .. .....c
... .. .. .. .. .. ...... .. .. .. .. ..c
....
.
.
.
.. .
.
.
.... ..
. .
.
.
.. .
......
......
..
.
......
..
....
..
.. .
.
.. ..
..
.. .......
. .
.
.. .
..
.c
.
..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
..
..
. ..
. ..
. ..
....
. ..
. .. .. .. .. .. .. .. .. .. .. ....c
. .. .....
. .. .. .. .. .. .. .. .. .. .c
.
.
.
.. ....
.
..
..
.
.
.
.
........................................................................ ......
.
.
.
.
..
..
.
.
..
..
.
.
..
..
.
-
x1
Das zugehörige LP-Problem hat die optimale Lösung x0 = ( 32 , 52 ) mit Kosten c(x0 ) = −4.
Unterteilt man nach der 1. Komponente, dann erhält man die beiden Teilprobleme
LP 1 : x1 ≤ 1
und
30
LP 2 : x1 ≥ 2.
x2
6
c(x) = −(x1 + x2 )
....
..
....
... ....
....
... ....
....
..
...
.
....
...
..
.
..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
....
. ..
. ....... .. .. .. .. .. ........ .. ..... .. .. .. .. .. .. ...... .. .. .. .. .
....
... .
. ...
.
... .
.... .
. ...
... .
. ..
......
.....
....
..
.
.
....
...
...
.
..
.
..
..
..
.
.
.
.
.
.
..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
.....
. ..
. .. .. .. .. .. .. .. .. .. .. ........ .. .. .. .. .. .. .. .. .. .. .. ..
...
...
...
..
..
..
..
..
..
..
..
.
.
...........................................................
..
..
..
...
...
...
..
..
..
..
..
..
c
....
.. . .....
.. ...c
.. . ....
...............
LP 1
c
c
.....
... ...
...c ...
... ....
.. .
..................
c
LP 2
-
x1
Das Problem LP2 z.B. hat die optimale Lösung x2 = (2, 32 ) mit Kosten c(x2 ) = − 72 . Unterteilt
man wieder (nach x22 ), dann erhält man die beiden Teilprobleme
LP 5 : x2 ≤ 1
LP 6 : x2 ≥ 2.
und
x2
6
.....
... ...
... .....
..
...
.
..
.
..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
....
. ..
. ....... .. .. .. .. .. ........ .. ..... .. .. .. .. .. .. .. .. .. .. .. .. .
... .
.. ....
..
... ..
.. ..
..
... ..
... ...
...
.....
....
.....
.
...
.
..
.
...
......
..
.
...
.. .
.
.
.
.. ...
..
.. ..
.
. ...
.. ...
.
..
.
..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ..
. ...
. ..
. ..
.....
. ..
. .. .. .. .. .. .. .. .. .. .. ......... .. ... .. .. .. .. .. .. .. .. .. ...
.....
.
.
.
..
.
.
.
..
.
.
..
.
.
.
.
...
..
..
..
..
.
..........................................................................................
...
.
.
..
..
..
.
.
.
..
..
..
.
.
.
LP 6
c
c
c
....c........
... ...
..................
c
c(x) = −(x1 + x2 )
....
....
....
....
....
....
....
....
....
c
LP 5
-
x1
LP5 hat die ganzzahlige optimale Lösung (2, 1) mit Kosten −3, die auch optimale Lösung für
das Ausgangs-ILP ist.
Man kann diesen Auswahlprozeß mit Hilfe eines Baums beschreiben. Die Wurzel entspricht der
ursprünglichen zulässigen Menge und jeder Knoten steht für ein Teilproblem.
0c
.... ....
...... ...........
.....
......
......
......
.
.
.
.
.
......
.
0 .......
0
......
1
.....
1 ............
1
.....
.
......
.
.
.
.
......
....
.
.
.
.
.
.....
...
.
.
.
.
.
.
.
.
.
......
..
..
......
.....
....
... ...
... ..
.. ....
.. ....
.
.
...
...
.
..
.
.
.
...
...
...
1
2 .....
...
...
...
...
... 2
..
2
2
..
.
.
...
.
.
...
.
.
..
...
.
.
...
.
..
...
.
.
.
.
..
.
..
..
x ≤ [x ]
≥ [x ] + 1
1c
x2 ≤ [x12 ]
3c
c2
≥ [x ] + 1
≤ [x ]
c4
5c
x ≥ [x22 ] + 1
c6
Wenn das ursprüngliche ILP eine beschränkte zulässige Lösungsmenge besitzt, muß der Verzweigungsprozess nach endlich vielen Schritten entweder mit einer ganzzahligen Lösung des
entsprechenden Teilproblems oder mit einem LP ohne zulässige Lösungen enden. Die ganzzahlige Lösung mit den geringsten Kosten ist die optimale Lösung des ILP.
Ist irgendwann eine ganzzahlige Lösung z mit Kosten c(z) gefunden und betrachtet man ein
Teilproblem (einen Knoten des Baums), für deren Lösungen die untere Schranke der Kosten
31
schon größer als c(z) ist, dann kommen ganzzahlige Lösungen dieses Teilproblems als optimale
Lösungen nicht in Betracht. Daher muß man die Verzweigungen dieses Knotens nicht weiter
untersuchen.
Für einen Algorithmus muß man nun festlegen, welchen Knoten man bei einer Verzweigung
weiterverfolgt, und welche nichtganzzahlige Komponente benutzt wird, um die zusätzlichen
Bedingungen einzuführen. Für beide Fragestellungen gibt es keine allgemein bestmögliche Wahl.
Es erscheint sinnvoll, den Knoten weiter zu verfolgen, der die kleinste untere Schranke hat.
Betreffend der Wahl der Komponenten wird die Komponente empfohlen, deren zugehörigen
Zusatzbedingungen die unteren Schranken möglichst weit nach oben drückt, in der Hoffnung, im
weiteren Pfad möglichst viele Knoten nicht berücksichtigen zu müssen, da die untere Schranke
schon zu groß ist.
Beispiel 3.6.1 (Forts.)
Der vollständige Baum zu unserem Beispiel ist
0c
z = −4
.... ....
..... .......... 0
......
......
......
......
......
......
.
.
.
.
......
....
.
.
1
1
.
......
.
....
.
.....
.
.
.
......
....
.
.
.
.
......
....
.
.
......
.
.
.
.
......
......
....
......
.
...... ..........
2
......
......
.
.
.
.
.
.....
5
...
.
.
......
.
.
.
......
....
.
.
.
.
.
......
.....
......
......
..... 2
2
......
......
......
......
.....
.
......
.
.
.
.
......
...
.
.
.
.
.
..
..
.
.
... ......... 3
.
.
.
.
.
......
.....
.
.
.
.
.
.
......
....
.
.
.
.
.
.
.
......
.....
......
......
...... 1
1
......
......
.....
......
.....
......
.
.
.
.
.
......
...
.
.
.
.
......
.
....
.
.....
.
.
.
.
.
x ≤1
z1 = −2.5 c 1
gelöscht durch x
x ≥2
c 2 z = −3.5
x ≤1
x ≥2
3 c z = −3.25
x ≤2
x ≥3
z5 = −3 c 5
ganzzahlig
c4
leer
c6
leer
Zusammenfassend gilt:
Gegeben sei ein Problem A mit zulässiger Menge G. Für die Durchführung des Branch-andBound-Verfahrens benötigt man nur zwei allgemeine Voraussetzungen:
S
1. Verzweigen (Branch): Für jedes F ⊂ G ist F =
Fi darstellbar mit disjunkten Fi .
Betrachtet man diese Fi als Knoten eines Graphen, so erhält man einen (gerichteten)
Baum.
2. Beschränken nach unten (Bound): Es gibt ein einfaches Problem B, so daß min B(F ) ≤
min A(F ) für jedes F ⊂ G gilt. (B liefert untere Schranken für die Knoten des Baums).
Bezeichnet man wie üblich die Nachfolger eines Knotens in einem gerichteten Baum als Kinder,
dann hat der Algorithmus die folgende allgemeine Form: Aktivmenge“ ist die Menge der
”
Knoten, die noch genauer untersucht werden muß, O ist eine obere Schranke für die Lösung,
Bestlösung“ ist die beste gefundene Lösung.
”
Algorithmus 3.6.2 (Branch-and-Bound)
begin
Aktivmenge := {G}; (* G ist das ursprüngliche Problem *)
32
O := ∞;
while Aktivmenge 6= ∅ do
begin
wähle einen Verzweigungsknoten k ∈ Aktivmenge;
Aktivmenge := Aktivmenge\{k};
Erzeuge die Kinder von Knoten k, Kind[i], i = 1, . . . , n k ;
Erzeuge die unteren Schranken zi = min B(i), i = 1, . . . , nk ;
for i = 1 to nk do
begin
if zi < O then
begin
if Kind[i] ist vollständige Lösung then
begin
if A(i) < O then
begin
O := A(i);
Bestlösung := Kind[i];
end;
end else Aktivmenge := Aktivmenge ∪ {Kind[i]};
end else lösche Kind[i];
end;
end;
end.
Beispiel 3.6.3 Als realistisches Beispiel für die Anwendung des Branch-and-Bound-Verfahrens
betrachten wir das TSP, für das kein Algorithmus mit polynomialer Komplexität bekannt ist,
speziell das Problem der Bestimmung einer optimalen Rundreise für die folgenden 5 mit ihren
Abständen gegebenen Städten
Ac
Bi
Dr
Fr
Ha
Ac
∞
257
659
505
488
Bi
257
∞
511
618
262
Dr
659
511
∞
728
502
Fr
505
618
728
∞
759
Ha
488
262
502
759
∞
Die Diagonaleinträge sind gleich ∞ gesetzt - dies kann man als Verbieten von Schleifen interpretieren. Eine Tour entspricht nun einer Permutation der 5 Städte, d.h. einer (verallgemeinerten)
Diagonalen der Abstandsmatrix W = (dij ). Zieht man nun von allen Elementen einer festen
Zeile eine positive Zahl δ ab, so daß die entstehende neue Matrix W 0 nichtnegative Elemente
hat, dann enthält jede Tour genau ein Element der Zeile. Ihre Länge, bezogen auf die neue Matrix W 0 ist also um δ kürzer als die Länge bezüglich W . Dasselbe gilt für die Spalten. Reduziert
man nun jede Zeile (um δi ) und jede Spalte (um j ) so weit, daß in der schließlich gewonnenen Matrix W ∗ mindestens ein Element 0 ist, dann verändert sich die Länge jeder Tour um
n
n
X
X
s=
δi +
j . Natürlich hat jede Tour bezüglich der Matrix W ∗ nichtnegative Länge, d.h.
i=1
j=1
33
s ist untere Schranke der Längen aller Touren des Ausgangsproblems.
Zeilenoperationen ergeben:
Ac
∞
0
157
0
226
Ac
Bi
Dr
Fr
Ha
Schranke:
5
X
Bi
0
∞
9
113
0
Dr
402
254
∞
223
240
Fr
248
361
226
∞
497
Ha
231
5
0
254
∞
mit
δi
257
257
.
502
505
262
δi = 1783.
i=1
Spaltenoperationen ergeben:
Ac
Bi
Dr
Fr
Ha
Ac
∞
0
157
0
226
Bi
0
∞
9
113
0
Dr
179
31
∞
0
17
Fr
22
135
0
∞
271
Ha
231
5
0
254
∞
j
0
0
223
226
0
mit
Schranke: s =
5
X
δi +
i=1
5
X
j = 1783 + 449 = 2232.
j=1
Die Menge der möglichen Touren läßt sich nun aufspalten danach, ob eine feste Kante (vi , vj )
enthalten ist oder nicht. Ist die Kante nicht enthalten, dann kann man den entsprechenden
Eintrag in der Matrix durch ∞ ersetzen und möglicherweise für diesen Fall s erhöhen. Ist die
Kante enthalten, dann kann keine Kante der entsprechenden Zeile bzw. Spalte in der Tour
auftreten, man kann also diese Zeile und Spalte streichen und mit der reduzierten Matrix
fortfahren. Außerdem kann die entgegengesetzt gerichtete Kante nicht in der Tour auftreten,
d.h. man kann den entsprechenden Eintrag ∞ setzen.
Es ist nun sinnvoll, eine solche Kante als Verzweigungskriterium zu wählen, für die im ersten
Fall (Tour enthält diese Kante nicht) man s um einen möglichst großen Wert erhöhen kann,
d.h. mit
dij = 0
und maximalem min{dik , k 6= j} + min{dlj , l 6= i}.
Zum Beispiel wählt man zu Beginn die Kante (Ac, Bi) aus und erhält
im Fall (Ac, Bi)
Bi
Dr
Fr
Ha
Ac
∞
157
0
226
Dr
31
∞
0
17
Fr
135
0
∞
271
Ha
5
0
254
∞
bzw.
s1
Bi
Dr
Fr
Ha
Ac
∞
157
0
209
Dr
26
∞
0
0
34
Fr
130
0
∞
254
Ha
0
0
254
∞
mit s1 = 2254
und im Fall ¬(Ac, Bi)
Ac
Bi
Dr
Fr
Ha
Ac
∞
0
157
0
226
Bi
∞
∞
9
113
0
Dr
179
31
∞
0
17
Fr
22
135
0
∞
271
Ha
231
5
0
254
∞
Ac
∞
0
157
0
226
s2
Ac
Bi
Dr
Fr
Ha
bzw.
Bi
∞
∞
9
113
0
Dr
157
31
∞
0
17
Fr
0
135
0
∞
271
Ha
209
5
0
254
∞
mit s2 = 2254.
In beiden Fällen ergibt sich dieselbe Schranke, denn aus der Symmetrie des Ausgangs-TSP
folgt, daß jeder Tour mit Kante (Ac, Bi) eine Tour mit ¬(Ac, Bi) entspricht und umgekehrt
(nämlich die Tour mit (Bi, Ac)). Man muß daher nur einen der Fälle weiterverfolgen. Als
Verzweigungsbaum ergibt sich
c s = 2232
. .
... ....... 0
....
....
....
....
...
....
.
.
.
....
..
.
.
.
....
....
....
.
.
....
...
.
.
....
..
.
.
.
....
..
.
.
....
.
...
. ....
.
.
1
.
....
..
.
.
.
.
....
....
....
...
....
....
....
...
....
....
.
.
....
.
....
....
.
.
....
..
.
.
.
....
..
.
.
....
.
..
.. ....
.
3
4
.
.
....
...
.
.
.
....
....
....
...
.
.
.
.
.
.
....
...
....
....
....
....
....
....
....
...
.
.
.
....
....
....
.
.
.
. ....
.
5
6
.
.
....
..
.
.
.
.
....
.
....
....
9
...
....
.
.
.
.
....
....
....
...
....
....
.
.
.
.
.
.
....
..
....
....
...
....
...
8
... ......
7
.
.
....
..
.
.
.
....
...
....
....
.
.
.
.
.
.
....
....
....
...
....
....
....
....
....
....
.
.
....
.
..
.
...
.
.
.
¬(Ac, Bi)
(Ac, Bi)
s = 2254 c
(Ha, Dr)
c s2 = 2254
wg.Symm.nicht
¬(Ha, Dr) berücksichtigt
s = 2254 c
¬(F r, Ac)
(F r, Ac)
s = 2254 c
¬(Dr, F r)
(Dr, F r)
s = 2254 c
(Bi, Ha)
s9 = 2254 c
Tour
¬(Bi, Ha)
c s = 2463
gelöscht wg.s9
c s = 2665
gelöscht wg.s
cs
leer
c s10
leer
mit den Lösungen (Ac, Bi, Ha, Dr, F r, Ac) bzw. der Umkehrtour und der minimalen Länge
2254.
3.7
Dynamische Programmierung
Wie beim Branch-and-Bound-Verfahren beruht das Verfahren der dynamischen Programmierung auf einer intelligenten Aufzählung aller zulässigen Punkte. Es werden aber nicht Lösungen
mit Hilfe von Schranken ausgeschlossen, sondern man arbeitet sich von der letzten Entscheidung
rückwärts (analog zum Beweis des Algorithmus von Dijkstra):
Muß man zur Gewinnung der optimalen Lösung eine Folge D1 , . . . , Dn treffen, dann braucht
man bei der Entscheidung Dk nur die Folgen D1 , . . . , Dk−1 zu betrachten, die zu optimalen
zulässigen Lösungen vor dieser Entscheidung führten.
Das Prinzip werde an folgender Anwendungen demonstriert:
Kann man die Eckenmenge eines Netzwerks N = (s, t, V, E) in disjunkte Mengen V0 = {s},
V1 , . . . , Vk , Vk+1 = {t} zerlegen, so daß in E nur Kanten der Form (u, v), u ∈ Vi , v ∈ Vi+1 ,
35
0 ≤ i ≤ k, auftreten, dann heißt N geschichtetes Netzwerk. Gesucht ist ein kürzester Weg
in einem solchen geschichteten Netzwerk von s nach t.
Beispiel 3.7.1
j
e
4 *
J
g
J
7 - eH
J
2
HH
5
J5
Hj
Hk
@
@ 2
J
e
@
@
H
HH
1J
*
3
@5 e
@
^
J
Hj
b
h
H
@
@
R
@e
R
@ e
6 - e
3 1 et
s e
H 2
H
*
2
4
@
@
HH
4
j
H l @
@
e
@
@
2
4 *
@3
4@
@
@
R
@e
R
@
1 - e
2 - e
H 3
c
f
i HH
Hj
H e
m
a
e
@
d
2 - e
1 @
V0 = {s}, V1 = {a, b, c}, V2 = {d, e, f }, V3 = {g, h, i}, V4 = {j, k, l, m}, V5 = {t}.
Beginnend bei Vk wird in einer Tabelle festgehalten, wie ein kürzester Weg von jedem v ∈ Vi
aus nach t verläuft. Dazu wird für jedes v der Nachfolger aus Vi+1 auf einem kürzesten Weg
und die zugehörige Länge festgehalten. Aus der Tabelle für Vk kann nun rückwärts die Tabelle
für Vk−1 bestimmen usw. bis man bei V0 angekommen ist. Nun kann man anhand der Tabellen
vorwärts den kürzesten Weg rekonstruieren.
Beispiel 3.7.1 (Forts.) Jeder Menge Vi wird eine Tabelle zugeordnet, die zu jeder Ecke der
Menge den nächsten Nachfolger und die entsprechende Länge angibt:


j k l m
g h i
 Knoten
 Knoten
Tabelle(4) =
Nachfolger t t t t
⇒ Tabelle(3) =
Nachfolger k k m


Länge
5 1 4 2
Länge
3 4 5


d e f
a b c
 Knoten
 Knoten
⇒ Tabelle(2) =
Nachfolger h h h
⇒ Tabelle(1) =
Nachfolger d d f


Länge
6 5 6
Länge
8 7 7

s
 Knoten
Nachfolger c
⇒ Tabelle(0) =

Länge
11
Der kürzeste Weg ist dann gegeben durch (s, c, f, h, k, t) mit Länge 11.
36
Inhaltsverzeichnis
3 Kombinatorische Optimierung
3.1 Begriffe aus der Graphentheorie . . . . . . . . . . . . . . .
3.2 Das Problem des kürzesten Wegs . . . . . . . . . . . . . .
3.3 Minimal spannende Bäume . . . . . . . . . . . . . . . . . .
3.4 Maximale Flüsse und der Algorithmus von Ford–Fulkerson
3.5 Kostenminimale Flüsse . . . . . . . . . . . . . . . . . . . .
3.6 Branch-and-Bound-Verfahren . . . . . . . . . . . . . . . .
3.7 Dynamische Programmierung . . . . . . . . . . . . . . . .
37
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
6
14
20
26
30
35
Index
Kante, 1
gerichtete, 2
Kantenzug, 3
geschlossener, 3
Kapazität
eines Schnittes, 20
obere, 5
untere, 5
Knoten, 1
Knoten–Kanten–Inzidenzmatrix, 6
kostenminimaler Fluß, 26
Kreis, 3
Kruskal–Algorithmus, 16
Adjazenzmatrix, 4
Algorithmus
gieriger, 18
von Dijkstra, 8
von Floyd–Warshall, 11
von Ford–Fulkerson, 23
von Kruskal, 16
von Prim, 15
Baum, 3
spannender, 3
bipartiter Graph, 2
Digraph, 2
Dijkstras Algorithmus, 8
Dreiecksoperation, 10
Länge eines Kantenzugs, 3
max flow problem (MFP), 20
Maximal weight forest (MWF), 17
Maximalfluß–Minimalschnitt–Satz, 22
MFP, 20
Minimal spannender Baum, 5
Minimal spanning tree (MST), 5, 14
Minimaler spannender Baum, 14
MST, 5, 14
MWF, 17
Ecke, 1
Floyd–Warshall–Algorithmus, 11
Fluß, 6
kostenminimaler, 26
Ford–Fulkerson–Algorithmus, 23
gerichtete Kante, 2
gerichteter Graph, 2
geschichtetes Netzwerk, 36
gewichteter Graph, 4
Gieriger Algorithmus, 18
Graph, 1
bipartiter, 2
gerichteter, 2
gewichteter, 4
schlichter, 2
vollständiger, 2
zusammenhängender, 3
Netzwerk, 5
geschichtetes, 36
Prim–Algorithmus, 15
Problem des kürzesten Wegs, 6
Problems des größten Flusses, 20
Quelle, 5
Rückwärtskante, 21
Satz
von Edmonds und Karp, 25
schlichter Graph, 2
Inzidenzmatrix, 6
Königsberger Brückenproblem, 1
38
Schnitt, 20
Senke, 5
shortest path problem (SP), 6
SP, 6
spannender Baum, 3
Teilgraph, 2
Traveling Salesman Problem (TSP), 4
TSP, 4
Vergrößerungsnetzwerk, 28
vollständiger Graph, 2
Vorwärtskante, 21
Wald, 14
maximaler, 17
Weg, 3
zunehmender, 21
Wert eines Flusses, 6
Ziel, 5
Zirkulation, 26
zunehmender Weg, 21
zusammenhängender Graph, 3
39
Herunterladen