Die k kürzesten Wege in gerichteten Graphen

Werbung
Die k kürzesten Wege in gerichteten Graphen
Marc Benkert
Wintersemester 2001/2002
1
Einführung
1.1
Problemstellung
In einem gerichteten, gewichteten Graphen G = (V, E) sollen die k kürzesten Wege zu zwei
vorgegebenen Knoten s, t gefunden werden.
1.2
Technische Voraussetzungen
Gegeben sei
• Graph G = (V, E), |V | = n, |E| = m
• Kantenfunktion l : E → R+
0
• Zykel, Selbst- und Mehrfachkanten sind erlaubt
• Startknoten s ∈ V
• Zielknoten t ∈ V
• jeder Knoten v ∈ V sei von s aus erreichbar
• ein s−t Weg darf an einem Knoten mehrmals vorbeikommen, Zykel dürfen also durchlaufen
werden
1.3
Motivation
Was bringt es uns zusätzlich zu der kürzesten Verbindung zweier Punkte auch noch die nächstkürzten zu kennen?
Eine Auswahl bezüglich anderer Kriterien als nur der Länge ist möglich. Ein Radfahrer wird
z.B. auf die Höhenmeter achten, die er auf einer Strecke zurückzulegen hat (kürzeste Wege im
Strassennetz).
Die Sensitvität der Lösungen (Ähnlichkeit) kann beitragen zum Verständnis der Aussage, die
der Graph illustrieren soll. Dies spielt vor allem in der Molekularbiologie eine Rolle. Allgemein
kann man sagen, daß man sich von der Kenntnis der k kürzesten Wege ein besseres Verständnis
der Aussage des Graphen verspricht, als von der Kenntnis lediglich eines kürzesten Weges.
1
1.4
Der vorgestellte Algorithmus
Der Algorithmus den ich im folgenden vorstellen werde ist sehr konstruktiv. Er benötigt die
Vorberechnung eines single destination shortest path tree. Die Destination wird in unserem Fall
der Knoten t sein. Ich erhalte den single destination shortest path tree, indem ich in G R einen
single source shortest path tree bzgl Knoten s bestimme, wobei GR den Graphen bezeichne, den
ich aus G durch umdrehen aller Kanten erhalte. Siehe hierzu Abb. 1.
Die erforderliche Laufzeit ist in O(m + n log n) [1] und ist somit verträglich mit der Laufzeit
O(m+n log n+k log k), die der Algorithmus zur Bestimmung der k kürzesten s−t Wege benötigt.
Zur Bestimmung der k kürzesten Wege von s zu allen anderen Knoten wird O(m + n log n +
nk log k) benötigt.
Die Idee des Algorithmus ist nun, einen s − t Weg durch einen beliebigen s − u und einen
kürzesten u − t Weg darzustellen. Dieser wird durch den single destination shortest path tree
induziert. Wir müssen nun wissen, wieviel man beim Laufen von s nach u bzgl eines kürzesten
s − t Weges an Länge verliere. Hierzu wird die Kantenpotentialfunktion δ(e) eingeführt. Abb. 2
2
Vorbereitungen des Algorithmus
2.1
Verwendete Bezeichnungen
• Graph G = (V, E), s, t ∈ V
• T ⊂ E shortest destination path tree zu t
• Für u, v ∈ V sei d(u, v) Distanz des kürzesten u − v Weges induziert durch T
• Für e ∈ E sei δ(e) = l(e) + d(target(e), t) − d(source(e), t) Kantenpotentialfunktion
• e ∈ G − T sidetrack-Kante
• nextT (v) Nachfolger von v in T
2.2
Darstellung der Lösungswege
Geben wir den kürzesten Weg explizit aus, so kann es passieren, daß der i-te kürzeste Weg die
Länge i · n hat. Dies ist z.B.
G aus einem Kreis. Summieren wir die Länge der
Pkder Fall, besteht
2
k Wege auf erhalten wir: i=1 i · n ∈ O(k · n), was doch eher schädlich wäre gegenüber unser
angestrebten Laufzeit des Algorithmus.
Da aber nun ein s − t Weg durch die verwendeten sidetrack-Kanten eindeutig bestimmt ist,
(zwischen den sidetrack-Kanten laufen wir auf T) genügt es diese auszugeben. Unsere Ausgabe
besteht dann aus einer Liste, die einen Pointer auf das Listenelement enthält, aus der der gespeicherte Weg durch Ausführen derselben sidetracks des in diesem Element gespeicherten Weges
plus Ausführen des letzten sidetracks, der ebenfalls im Listeneintrag gespeichert ist, hervorgeht.
Darüberhinaus kann z.B. die Länge des Weges gespeichert werden.
Die Ausgabe des i-ten Weges benötigt in unserer impliziten Darstellung also nur noch konstante
2
3
s
4
2
b
e
4
h
12
10
2
6
4
8
2
5 11
9
3
4
a
2
3
1
3
3
c
f
4
i
3
10
2
6
3
1
3
2
3
4
3
1
4
8
1
4
d
g
4
t
11
6
7
Abbildung 1: Beispielgraph und single destination shortest path tree
1
12
10
6
4
2
9 7
6
2
8
10
6
3
1
4
3
10
0
13
11
7
0
Abbildung 2: Kantenpotentialfunktion δ(e)
3
0
Zeit, womit wir unser Problem gelöst hätten. Der explizite Weg läßt sich proportional zur Anzahl der Kanten des Weges berechnen.
Sicherzustellen ist allerdings noch, daß die angegebenen sidetrack-Kanten überhaupt einen s − t
Weg induzieren, sowie daß der Vorgänger-Weg eines Weges, induziert durch Weglassen des letzten sidetrack, vor dem Weg selbst ausgegeben wird. Dies wird 2.3.3 sichern.
2.3
2.3.1
Erste Folgerungen
Folgerung
(i) Für e ∈ E gilt δ(e) ≥ 0
(ii) Für e ∈ T gilt δ(e) = 0
Beweis:
(i) Wäre δ(e) < 0 stände dies im Widerspruch dazu, daß T ein single destination shortest
path tree ist.
(ii) Für solche e gilt: l(e) = d(source(e), t) − d(target(e), t) somit erhalte ich die Behauptung
direkt aus der Definition von δ.
2.3.2
Lemma
P
Für jeden s − t Weg p gilt l(p) = d(s, t) + e∈p δ(e)
Beweis:
Dies wird offensichtlich, da δ(e) den Verlust angibt, den ich bzgl des Weges, der in source(e)
startet, e benutzt und dann auf T nach t läuft gegenüber dem Weg, der sofort von source(e)
auf T nach t läuft, habe.
P
P
Ein mathematischer
P e∈p l(e) = e∈p δ(e)+d(source(e), t)−d(target(e), t) =
P Beweis wäre: l(p) =
d(s, t) + d(t, t) + e∈p δ(e) = d(s, t) + e∈p δ(e).
2.3.3
Folgerung
Für jeden s − t Weg p = (e1 , e2 , ..., en ) gilt für den s − t Weg p− = (e1 , e2 , ..., en−1 ): l(p) ≥ l(p− ),
wobei ei den i.ten sidetrack bezeichne.
Beweis:
Folgt direkt aus 2.3.1 (i) und 2.3.2.
2.4
Der Kürzeste-Wege-Baum (gradunbeschränkt)
Wir bilden nun einen Baum, dessen Knoten aus s−t Wegen bestehen. Dabei stehen in den Knoten
jeweils die ausgeführten sidetracks. Die Wurzel besteht aus der leeren Menge, also dem kürzesten
s − t Weg laut T. Die sidetracks eines Kindes bestehen aus den sidetracks des Vorgängers sowie
einem weiteren sidetrack. Hierbei muss man natürlich aufpassen, welche sidetracks ausführbar
sind. 2.3.3 liefert uns eine Heap-Ordnung auf dem Baum: Man weiß, daß die Kinder eines Knotens einen höchstens längeren s − t Weg induzieren als der Knoten selbst.
4
{}
13
2
3
21
22
23
1
9
8
19
1,7
1,6
1,2
1,4
1,13
24
25
26
27
28
10
18
16
8,7
17
8,7,8
20
Abbildung 3: Kürzester Wegebaum, sidetrackkanten per δ identifiziert
Abbildung 3 zeigt einen Ausschnitt dieses Baumes für unseren Beispielgraphen.
Man erkennt, daß der Baum durchaus unendlich sein kann. In der Abbildung ist dies anhand
des Zykels, der durch die sidetrackkanten (8,7) induziert wird, verdeutlicht.
Wir brauchen uns allerdings gar nicht erst zu fragen, wieviel Laufzeit benötigt würde, diesen
Baum zu erstellen, da das Suchen nach den k kürzesten Wegen in diesem Baum sowieso schon
mehr Laufzeit verschlingen würde, als wir für unseren Algorithmus veranschlagt haben. Zur
Erinnerung: Dies war O(m + n log n + k log k)
2.5
Das Auffinden der k kürzesten Wege in einem Wegebaum
Allgemeiner gesagt suchen wir die k kleinsten Knotenwerte in einem Heap H mit der Restriktion,
daß die Nachfolgeknoten einen geringeren Wert haben.
Bei uns ist der Heap H der kürzeste Wegebaum, und die Knotenwerte sind die Summen der
δ − W erte der sidetrackkanten.
5
Geschickterweise geht man folgendermaßen vor:
Man fügt die Wurzel von H in einen neuen Heap F ein. Solange noch keine k Knoten ausgegeben
worden sind oder der Heap F leer ist (dies wäre der Fall hätte Heap H gar keine k Knoten,
in unserem Fall würden also keine k s − t Wege existieren) fügt man alle Kinder der aktuellen
Wurzel von F in F ein, entnimmt die aktuelle Wurzel aus F und gibt sie aus.
Alles in allem eine normale Breitensuche in einem Heap. d bezeichne nun die Anzahl der maximal
möglichen Kinder eines Knotens. Die Breitensuche wird also Laufzeit O(d · k + k log k) erfordern.
Dabei brauchen wir O(d · k) um den Heap F aufzubauen und O(k log k) für die solange-Schleife.
Zu beachten ist hierbei, daß ein Heap in Linearzeit aufgebaut und in logarithmischer Zeit aktualisiert werden kann.
In unserem Fall sind die Kinder aber nur durch die Anzahl aller Kanten m beschränkt. Hierzu
stelle man sich einen ausreichend dichten Graphen (Anzahl der Kanten von T fällt nicht ins
Gewicht) vor, dessen single destination shortest path tree T aus einem einzigen Weg bestehe.
Dies führt zu einer Laufzeit von O(m · k + k log k) für die Breitensuche führen. Diese könnte
wiederrum unsere veranschlagte Laufzeit dominieren!
Die folgenden Konstruktionen haben deshalb nur ein Ziel: Einen Kürzesten-Wege-Baum zu erstellen, dessen Knoten konstant viele Nachfolger haben.
In diesem Fall veranschlagt die Laufzeit der Breitensuche O(k log k) und verschlechtert die asymptotische Laufzeit des Algorithmus somit nicht mehr.
3
Konstruktion des Kürzesten-Wege-Baums (gradbeschränkt) Der Algorithmus
Man konstruiert einen Graphen P (G) der einen Initialknoten r(s) enthalten wird und in dem alle
Knoten maximal vier auslaufende Kanten haben. Der Kürzeste-Wege-Baum wird dann induziert
durch alle von r(s) aus erreichbaren Knoten. Jeder Knoten hat also höchstens vier Nachfolger.
Man geht dabei wie folgt vor:
(i) Bilde für jeden Knoten v ∈ V einen 3-Heap HG (v) bestehend aus allen sidetrackkanten die
ich von v aus auf dem durch T induzierten v − t Weg erreichen kann. Die Heap-Ordnung
wird dabei gegeben durch die δ-Werte, der geringste Wert landet wieder in der Wurzel.
(ii) Bilde mit all diesen Heaps einen azyklischen Graphen D(G) in dem jeder Knoten einer
Kante in G − T entspricht und höchstens drei auslaufende Kanten hat.
(iii) Bilde aus D(G) den gewünschten Graphen P (G) mit höchstens vier auslaufenden Kanten
Die Konstruktionen im einzelnen:
3.1
Der Heap HG (v)
Wiederrum sind drei Schritte erforderlich
(i) Zunächst werden für alle Knoten 2-Heaps Hout (v) gebildet bestehend aus den von v direkt
auslaufenden sidetrackkanten unter den üblichen Bedingungen. Hinzu kommt die Restriktion, daß die Wurzel nur einen Nachfolger haben darf.
6
Die erforderliche Laufzeit für einen Heap ist O(|out(v)|). Die Laufzeit für alle diese Heaps
beträgt O(m) da jede Kante maximal einmal in einen Heap eingefügt wird.
(ii) Nun bildet man für jeden Knoten einen 2-Heap HT (v), der für alle Knoten w auf dem v − t
Weg in T die Wurzel von Hout (w) enthält.
Bilde hierfür zunächst HT (t) und laufe dann die Wege in T rückwärts entlang. Der Heap
HT (v) wird gebildet, indem man die Wurzel von Hout (v) in den bereits existierenden Heap
HT (nextT (v)) einfügt.
Die Laufzeit beträgt somit im worst-case (T ein Weg) O(n) für diesen Schritt.
(iii) Der Heap HG (v) entsteht nun, indem die entsprechenden Heaps Hout (w) in den Heap
HT (v) eingesetzt werden.
Die Tatsache, daß der Heap HT (v) ein 2-Heap ist und die Restriktion in (i) sichern die
3-Heap-Eigenschaft von HG (v)
Die Laufzeit zur Bildung von HG (v) ist also O(n + m)
Als Beispiel für diese Konstruktion diene der Weg s, a, c, f, t in unserem Beispielgraphen. Die
Heaps Hout ergeben sich sofort zu:
• Hout (t) = 13
• Hout (f ) = 8
• Hout (c) = 9 → 10
• Hout (a) = 3
• Hout (s) = 1 → 2
Die Heaps HT sowie den Heap HG (s) entnehmen Sie der Abbildung 4. Die Knoten werden wiederrum durch die δ-Werte der Kanten identifiziert, denen sie entsprechen. Die *-Knoten
werden von der Heapify-Operation, die die Wurzel von Hout (w) in HT (nextT (w)) einfügt, aktualisiert. Knoten, die kein * bekommen haben, werden später in D(G) dieselben Struktureigenschaften der Heaps HG ausnützen. Für sie wird nämlich in D(G) nur ein Knoten eingefügt
werden. Dies ist besonders wichtig, um zu gewährleisten, daß die Anzahl der Knoten in D(G)
nicht explodiert! Siehe hierzu auch Eigenschaften von D(G).
3.2
Der Graph D(G)
Der Graph D(G) hat für jeden Knoten aus Hout , der nicht Wurzel ist (Typ 1), sowie für jeden *Knoten in HG (Typ 2) einen Knoten. Ansonsten übernimmt er die HG -Struktur. Beachte dabei,
das Kanten zu Nicht-*-Knoten auf den letzten entsprechenden *-Knoten der Vorgänger-Heaps
gerichtet sind. Abbildung 5 zeigt D(G) für unseren Beispielgraphen.
Eigenschaften von D(G)
• D(G) ist azyklisch.
7
8*
8*
13*
9*
13*
HT (t)
13
HT (f )
HT (c)
3*
1*
8*
13
3*
9*
13
9
8*
HT (s)
HT (a)
1*
3*
9
2
13
8*
HT (s)
Abbildung 4: Heaps HT und Heap HG (s)
8
b
2
e
2
4
7
h
2
4
i
4
4
d
t
13
13
g
f
8
0
8
c
a
8
3
9
8
13
s
1
3
2
6
10
9
8
Abbildung 5: Graph D(G)
• Jeder Knoten w ∈ D(G) kann mit einer Kante ew ∈ G identifiziert werden
• Jeder Knoten v ∈ G kann mit einem Knoten h(v) ∈ D(G) identifiziert werden, wobei h(v)
gerade der Wurzelknoten von HG (v) ist, der immer ein *-Knoten ist.
• Die in D(G) von h(v) aus erreichbaren Kanten bilden den Heap HG (v), insbesondere hat
jeder Knoten also maximal drei auslaufende Kanten.
• D(G) hat O(m + n · log n) viele Knoten. Dies entspricht auch der benötigten Laufzeit,
D(G) zu erstellen, da die Heaps HG vorbestimmt waren.
Den letzten Punkt schauen wir uns noch etwas genauer an:
Da Knoten des Typs 1 mit sidetrackkanten in G identifiziert werden können, existieren maximal
m − (n − 1) Knoten des Typs 1 (|T | = n − 1).
Knoten vom Typ 2 sind etwas aufwendiger zu zählen. Beim Erstellen des Heaps HG (v) werden
blog2 ic + 1 Knoten durch die Heapify-Operation beim Einfügen der Wurzel von Hout (v) in
HT (nextT (v)) aktualisiert. Wobei i hier die Anzahl der Knoten auf dem v−t Weg in T bezeichnet.
Im
worst-case ist T wieder
Pnein Weg. Die Anzahl Typ2-Knoten beläuft sich dann auf
Pn−1
i=1 log2 i ≤ n + n · log2 n
i=1 blog2 ic + 1 ≤ n +
Typ1 und Typ2-Knoten aufsummiert ergeben somit O(m + n · log n) viele Knoten.
3.3
Der Graph P (G)
Im Graphen D(G) bilden die von h(s) erreichbaren Knoten gerade den Heap H G (s). Ich kann
somit den in h(s) startenden und in w ∈ D(G) endenden Weg identifizieren mit dem s − t Weg
in G, der auf T läuft und lediglich die Kante ew als sidetrackkante benutzt.
9
In den meisten Graphen kann ich aber mehrere sidetracks ausführen. Ich muss dies also durch
Einfügen zusätzlicher Kanten in D(G) gewährleisten. Hierzu wird für jeden Knoten w ∈ D(G),
der zu der sidetrackkante (u, v) ∈ G gehört, ein Kante (w, h(v)) eingefügt. Dies ist sinnvoll, da
ich von h(v) den Heap HG (v) erreiche, also alle von h(v) ausführbaren sidetracks.
Der Graph P (G) entsteht also aus D(G) durch Einfügen dieser Kanten, sowie Einfügen eines Initialknotens r(s) und einer Initialkante (r(s), h(s)). Da wir aus P (G) unsere kürzesten s−t Wege
ablesen wollen, benötigen wir eine Kantenfunktion, die angibt wieviel wir bzgl des kürzesten s−t
Weges an Länge verlieren.
Da P (G)-Wege, die in r(s) starten, mit s − t Wegen in G identifiziert werden sollen, geschieht
dies wie folgt:
• Die Initialkante (r(s), h(s)) bekommt das Gewicht δ(h(s))
wobei mit δ(h(s)) der δ-Wert der sidetrackkante gemeint ist, die zu h(s) gehört.
• Kanten (u, v), die schon in D(G) existierten, bekommen Gewicht δ(v) − δ(u)
• Hinzugefügte Kanten (w, h(v)) bekommen Gewicht δ(h(v))
Die Wegindentifizierung läuft nun folgendermassen ab:
Der leere Weg in P (G) induziert den kürzesten s − t Weg laut T. Steige ich von r(s) zu h(s)
ab, bedeutet dies, daß ich mindestens einen sidetrack ausführe. Da nun alle Knoten des Heaps
HG (s) erreichbar sind, welche ja gerade alle von s erreichbaren sidetrackkanten identifizieren,
wähle ich den auszuführenden sidetrack, indem ich zum entsprechenden Knoten in HG (s) laufe.
Dabei wird ein sidetrack jeweils signifikant, falls der P (G)-Weg endet, oder ich wieder zu einem
h(v)-Knoten aufsteige. Im Fall des Aufsteigens befinde ich mich im Heap HG (v) und wähle hier
wiederrum einen sidetrack, den ich ausführen möchte. Dieses Vorgehen kann ich beliebig iterieren.
Die Gewichte in P (G) sind so gewählt, daß die Länge des in r(s) startenden Weges den Verlust
bzgl des kürzesten s − t Weges angibt. Man verdeutliche sich diesen Sachverhalt, indem man in
D(G) selbst ein paar geeignete Kanten einfügt!
Eigenschaften von P (G)
• P (G) hat O(m + n · log n) viele Knoten, im Vergleich zu D(G) kommt lediglich der Initialknoten hinzu.
• P (G) kann in O(m + n · log n) erstellt werden, da ich lediglich alle Knoten in D(G) betrachten muss, und für diese eine weitere Kante einzufügen habe.
• Jeder Knoten v ∈ P (G) hat maximal vier auslaufende Kanten, da D(G) maximal drei
auslaufende Kante hat und eine Kante pro Knoten dazukommt.
• Jede Kante e ∈ P (G) hat ein positives Gewicht. Dies wird durch die Heap-Eigenschaft von
HG und dadurch, daß alle Einträge im Heap nicht negativ sind gewährleistet.
• Jeder in r(s) startende Weg in P (G) entspricht einem s − t Weg in G und umgekehrt
10
• Für die Länge L eines solchen Weges in P (G) gilt:
d(s, t) + L = l(induzierter s − t Weg)
Somit liefert mir die von r(s) in P (G) erreichbaren Knoten den Heap, in dem ich die in 2.5.
vorgestellte, gradbeschränkte Breitensuche zum Auffinden der k kürzesten s − t Wege laufen
lassen kann.
Die Gesamtlaufzeit beträgt somit O(m + n log n + k log k), O(m + n log n) für das Erstellen von
P (G) und O(k log k) für die anschliessende Breitensuche.
4
4.1
Variationen des Problems und abschliessendes Beispiel
Die k kürzesten Wege von s zu allen Knoten
Die gemachte Konstruktion löst primär das Problem, kürzeste Wege von allen Knoten zu t zu
finden. (Einfügen weiterer Initialknoten r(v) in P (G) für beliebigen Knoten v ∈ G)
Man behilft sich wieder durch GR . Dieselbe Konstruktion wird in GR mit Zielknoten s ausgeführt. Die gefundenen kürzesten Wege von allen Knoten zu s in GR korrespondieren somit zu
den gesuchten kürzesten Wegen von s in G.
Da wir die Breitensuche nun für jeden Knoten laufen lassen, ergibt sich die Laufzeit zu
O(m + n log n + n · k log k).
4.2
Wege kürzer als vorgebene Grenze
Wir können natürlich auch alle s − t Wege bestimmen, die kürzer sind als eine vorgegebene
Grenze. Das Abbruchkriterium der Breitensuche verändert sich einfach zu: Solange der gefundene
Weg eine Länge ≤ Grenze hat.
4.3
Kürzeste Wege in Graphen mit negativen Kantengewichten
Mit der Einschränkung, daß der Graph keine Zykel negativer Länge enthalten darf (denn dann ist
der kürzeste Weg nicht bestimmt) funktioniert der Algorithmus auch in Graphen mit negativen
Kantengewichten. Man muss allerdings noch die Laufzeit beachten, die man für das Finden
eines single source shortest path tree in einem solchen Graphen benötigt. Diese beläuft sich auf
O(m · n) [2].
4.4
Die k längsten Wege
In azyklischen Graphen (das Problem eines negativen Zykels eleminiert sich also von selbst)
können die k längsten Wege gefunden werden, indem man alle Kantengewichte negiert und in
G− alle kürzesten Wege sucht. Diese induzieren die k längsten Wege in G.
Hierzu noch folgendes Beispiel:
4.5
Das 0-1 KnapsackProblem
Gegeben seien n Objekte, von denen jedes allerdings nur einmal vorhanden ist. (→ 0-1). Die
Objekte haben Volumen ci ∈ N sowie Wertigkeiten wi ∈ R+ .
11
Das übliche Knapsack Problem
P besteht nun darin, den Sack
P mit Volumen L ∈ N möglichst
wertvoll aufzufüllen. Formell:
xi · wi unter der Bedingung
xi · ci ≤ L zu maximieren. Wobei
xi = 1 falls wir das Objekt i nehmen, 0 sonst.
Zur Lösung bildet man den Graphen G, der zwei ausgezeichnete Knoten s,t besitzt, sowie für
alle i = 1 . . . n + 1 und alle j = 0 . . . L einen Knoten i, j. Von s zu jedem Knoten 1, j verläuft
eine Kante mit Gewicht 0, von jedem Knoten i, n + 1 verläuft eine Kante zu t mit Gewicht 0.
Für jeden Knoten i, j mit j < n + 1 verläuft eine Kante zu i + 1, j mit Gewicht 0, und eine
Kante zu i + 1, j + ci mit Gewicht wi, falls j + ci ≤ L.
Abbildung 6 zeigt den Graphen G für folgende Werte:
L=5
c1 = 5, w1 = 8
c2 = 3, w2 = 4
c3 = 2, w3 = 5
c4 = 1, w4 = 2
c5 = 3, w5 = 5
Stehe ich beim Knoten i, j bedeutet dies, daß ich schon j viel Raum verbraucht habe. Nehme
ich eine Querkante, so ist xi =0. Nehme ich eine Kante nach unten, so ist xi = 1.
Der gebildete Graph ist azyklisch. Ich kann also laut 4.4 die längsten s − t Wege suchen, die mir
die besten Lösungen für das Knapsack Problem liefern. Berücksichtigen muss ich allerdings, daß
mir zwei verschiedene Wege eine gleiche Lösung induzieren können.
Literatur
[1] M.L.Fredman and R.E.Tarjan. Fibonacci heaps and their uses in improved network optimization algorithms. J.Assoc Comput.Mach. 34:596-615. Assoc.for Computing Machinery, 1987.
[2] A.V.Goldberg. Scaling algorithms for the shortest paths problem. SIAM J.Computing
24(3):494-504. Soc.Industrial and Applied Math., June 1995
[3] David Eppstein. Finding the k shortest paths, SIAM J.Computing, Vol.28(2), 652-673, 1998
12
1,0
2,0
3,0
4,0
5,0
6,0
5,1
6,1
2
1,1
2,1
3,1
5
4,1
2
4
5
5
s
1,2
2,2
8
3,2
4,2
4
5,2
6,2
5
2
5
1,3
2,3
3,3
4,3
5,3
2
4
6,3
5
5
1,4
2,4
3,4
4,4
5,4
6,4
5,5
6,5
2
1,5
2,5
3,5
4,5
Abbildung 6: Graph zum 0-1 Knapsack Problem
13
t
Herunterladen