Problem des Handlungsreisenden 1 Problem des

Werbung
Prof. Thomas Richter
Institut für Analysis und Numerik
Otto-von-Guericke-Universität Magdeburg
[email protected]
8. Juni 2017
Material zur Vorlesung Algorithmische Mathematik II am 08.06.2017
Problem des Handlungsreisenden
1 Problem des Handlungsreisenden
Wir formulieren zwei Probleme
Folie 1
Gegeben sei ein zusammenhängender, gewichteter Graph G = (V, E, fE ) sowie eine
Menge von Knoten
S = {s1 , . . . , sk ∈ V}.
Gesucht ist der Pfad
e
em−1
e
1
2
x1 −→
x2 −→
· · · −−−→ xm
welcher alle Knoten si ∈ S in beliebiger Reihenfolge besucht und kleinstes summiertes Kantengewicht hat
m−1
X
fE (ei ) → min
i=1
Folie 2
Gegeben sei ein vollständiger (d.h. zu x, y ∈ V existiert die Kante e = (x, y) ∈ E),
gewichteter Graph G = (V, E, fE ). Gesucht ist der Kreis, welcher alle Knoten des
Graphen genau einmal besucht und dabei kleinstes summiertes Kantengewicht hat.
n
X
fE (ei ) → min
i=1
Wir werden im Folgenden ausschließlich dieses Problem bei Betrachtung eines vollständigen Graphen untersuchen. Die Speicherung eines solchen Graphen ist einfach. Da
jeder Knoten mit jedem anderen Knoten verbunden ist speichern wir lediglich die n2
Gewichte in einer Matrix A ∈ Rn×n . Wir gehen weiter davon aus, dass diese Matrix
symmetrisch ist.
1
Folie 3
Definition 1 (Symmetrisches Handlungsreisendenproblem). Es sei G = (V, E, fE )
ein vollständiger gewichteter Graph mit n = |V| Knoten und Gewichtsmatrix A ∈ Rn×n .
Im Fall fE (e) = fE (e 0 ) für Kanten e = (x, y) und e 0 = (y, x), d.h. im Fall A = AT heißt
das Handlungsreisendenproblem symmetrisch.
Definition 2 (Metrisches Handlungsreisendenproblem). Es sei G = (V, E, fE ) ein
vollständiger gewichteter Graph mit n = |V| Knoten. Falls für drei Knoten x, y, z ∈ V und
Kanten e = (x, z), e1 = (x, y) und e2 = (y, z) stets gilt
fE (e) 6 fE (e1 ) + fE (e2 ),
also
∀i, j, k ∈ {1, . . . n}
Aik 6 Aij + Ajk
so heißt das Handlungsreisendenproblem metrisch.
In der Anwendung treten sowohl symmetrische als auch unsymmetrische Probleme
auf. Die Routenplanung kann z.B. Einbahnstraßen, Baustellen, unterschiedliche Tempolimits berücksichtigen. Metrische Probleme treten z.B. beim Bohren von Löchern in Leiterplatten auf (eine Anzahl an Löchern in vorgegebener Position muss möglichst schnell
gebohrt werden, im Anschluss muss der Bohrer wieder zurück). Auch bei der Navigation scheint es sich um ein metrisches Problem zu handeln. Umwege können sich aber
durchaus lohnen, je nachdem welches Verkehrsmittel, welche Straße verwendet wird.
2
Beim symmetrischen Problem muss nur die Hälfte der Kanten gespeichert werden. Wir
beachten diese Optimierung hier jedoch nicht und speichern einen vollständigen metrischen Graphen in folgender einfacher Struktur.
Folie 4
Algorithmus 1: Vollständiger, gewichteter Graph
1
2
3
4
c l a s s VGGraph
{
public :
v e c t o r < v e c t o r <double> > A;
5
VGGraph ( )
{ }
VGGraph ( i n t n )
{
A. r e s i z e ( n , v e c t o r <double> ( n , − 1 . 0 ) ) ;
}
6
7
8
9
10
11
12
void I n i t Z u f a l l ( i n t n )
{
A. r e s i z e ( n , v e c t o r <double> ( n , − 1 . 0 ) ) ;
13
14
15
16
Zufallszahlengenerator Z;
v e c t o r <double> X( n ) ,Y( n ) ; / / f ü r m e t r i s c h e n Graphen
int
MI = 1 0 0 0 0 0 0 ;
double MX = s q r t ( n ) ;
f o r ( i n t i = 0 ; i <n;++ i )
{
X[ i ] = 1 . 0 /MI∗Z ( 0 , MI ) ∗MX;
Y[ i ] = 1 . 0 /MI∗Z ( 0 , MI ) ∗MX;
}
f o r ( i n t i = 0 ; i <n;++ i )
f o r ( i n t j = i ; j <n;++ j )
{
double d=max ( f a b s (X[ i ]−X[ j ] ) , f a b s (Y[ i ]−Y[ j ] ) ) ;
A[ i ] [ j ]=A[ j ] [ i ]=d ;
}
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
}
32
33
};
3
2 Exakte Berechnung der Lösung
Es ist nun G = (V, E, fE ) ein vollständiger Graph und wir suchen einen Kreis, der jeden Knoten genau einmal besucht (und wieder am Startpunkt ankommt). Die Angabe
einer Lösung kann somit durch Angabe der Reihenfolge der durchlaufenden Punkte
angegeben werden.
Folie 5
Satz 1 (Startpunkt). Es sei G = (V, E, fE ) ein vollständiger symmetrisch gewichteter
Graph und
x1 → x2 → · · · → xn → x1
eine optimale Lösung des Handlungsreisendenproblems. Dann ergibt sich eine weitere optimale Lösung für jeden beliebigen Startpunkt als
xk → xk+1 → · · · xn → x1 → · · · → xk−1 → xk .
Jede dieser Lösungen ist auch in umgekehrter Reihenfolge optimal.
Beweis. Alle diese Lösungen beinhalten die Kanten (xk , xk+1 ) für k = 1, . . . , n − 1 sowie die Kante (xn , x1 ), gegebenenfalls in unterschiedlicher Reihenfolge. Das summierte
Kantengewicht ist stets gleich.
Da fE ((x, y)) = fE ((y, x)) so ist auch in umgekehrter Reihenfolge ein Kreis mit gleichem
Gewicht gegeben.
Die Schwierigkeit des Handlungsreisendenproblems liegt in der sehr großen Anzahl an
verschiedenen Kreisen.
Folie 6
Satz 2 (Anzahl an Lösungen). Es sei G = (V, E, fE ) ein vollständiger symmetrisch
gewichteter Graph mit n = |V| Knoten. Es gibt
(n − 1)!
2
potentiell verschiedene Kreise.
Beweis. Wir haben bereits gezeigt, dass die Wahl des Startknotens nicht relevant ist und
wählen daher ohne Einschränkung x1 = 1.
4
Es bleiben n − 1 Möglichkeiten zur Wahl von x2 , n − 2 zur Wahl von x3 usw. Insgesamt
ergeben sich auf diese Weise (n−1)! verschiedene Kreise. Jeder von diesen Kreisen wird
in beide Richtungen durchlaufen.
Mit diesem Ergebnis erhalten wir sofort eine “Lösung” des Problems.
Folie 7
Satz 3. Es sei G = (V, E, fE ) ein vollständiger gewichteter symmetrischer Graph mit n =
|V| Knoten. Das Handlungsreisendenproblem lässt sich in
O(n!)
Operationen lösen.
Als Beweis geben wir einen Algorithmus an.
Folie 8
Algorithmus 2: Exakte Lösung des Handlungsreisendenproblems
1
2
3
4
Setze f = ∞
Für a l l e Permutationen von (1, x2 , . . . , xn ) ∈ (1, 2, . . . , n)
Pn−1
Berechne f = fE (xn , x1 ) + j=1
fE ((xj , xj+1 ))
F a l l s f < fmin merke Permutation
Beweis. Es gibt (n − 1)!/2 relevante Permutationen. Für jede dieser Permutationen lässt
sich die Kantensumme in O(n) Operationen berechnen. Hiermit ergibt sich der entsprechende Aufwand.
5
Folie 9
Definition 3 (Lexikographische Ordnung). Für zwei Listen l = l1 , . . . , ln und r =
r1 , . . . , rn definieren wir
li = ri i = 1, . . . , k − 1 6 n
l<r ⇔
lk < rk
Auf diese Weise erzeugen wir eine Ordnung auf den Permutationen, z.B.
(1, 2, 3) < (1, 3, 2) < (2, 1, 3) < (2, 3, 1) < (3, 1, 2) < (3, 2, 1)
Idee für Algorithmus:
• Gegeben Permutation p1 , . . . , pn
• Bestimme nächste Permutation bzgl. der lexikographischen Ordnung
• Vorteil: es gibt eine erste (kleinste) und letzte (größte) Permutation
6
In C++ ist dieses Vefahren implementiert und kann einfach verwendet werden
Folie 10
1
2
3
# include < v e c t o r >
# include <iostream >
# include <algorithm > / / h i e r s i n d P e r m u t a t i o n e n d e f i n i e r t
4
5
using namespace s t d ;
6
7
8
9
10
11
i n t main ( )
{
vector <int > a ;
f o r ( i n t i = 0 ; i <3;++ i )
a . push_back ( i ) ;
12
do { cout << a [ 0 ] << " ␣ " << a [ 1 ] << " ␣ " << a [ 2 ] << endl ; }
while ( next_permutation ( a . begin ( ) , a . end ( ) ) ) ;
13
14
15
cout << endl ;
16
17
do { cout << a [ 0 ] << " ␣ " << a [ 1 ] << " ␣ " << a [ 2 ] << endl ; }
while ( next_permutation ( a . begin ( ) +1 , a . end ( ) ) ) ;
18
19
20
cout << endl ;
a [0]=7;
a [1]=2;
a [2]=0;
21
22
23
24
25
do { cout << a [ 0 ] << " ␣ " << a [ 1 ] << " ␣ " << a [ 2 ] << endl ; }
while ( next_permutation ( a . begin ( ) , a . end ( ) ) ) ;
26
27
28
return 0 ;
29
30
}
Folie 11
Iteratoren
Für einen Vektor vector<int> a geben die Funktionen a.begin() und a.end() Iteratoren
zurück. Ein Iterator ist im wesentliche ein Zeiger auf eine Speicherstelle. a.begin()
,→ zeigt auf den Speicher, an dem der erste Eintrag im Vektor steht. a.end() auf die
Speicherstelle hinter den letzten Eintrag.
Mit Iteratoren kann gerechnet werden. a.begin()+1 zeigt auf die Speicherstelle des
zweiten Eintrags, a.end()−1 auf den letzten Eintrag.
7
Folie 12
Die Laufzeit steigt enorm schnell:
n
Minimale Länge
Zeit
n
Minimale Länge
Zeit
3
4
5
6
7
8
1.52839
2.02879
2.42862
2.54813
3.03082
3.03082
1.97 · 10−6
2.40 · 10−6
3.29 · 10−6
5.21 · 10−6
1.38 · 10−5
8.49 · 10−5
9
10
11
12
13
14
3.10372
3.10648
3.12038
3.19257
3.21485
3.21485
5.77 · 10−4
5.42 · 10−3
5.40 · 10−2
6.30 · 10−1
8.22 · 10−0
1.38 · 10+2
Die Länge des Weges steigt hier monoton, da dem Graphen jedes mal nur ein neuer
Knoten hinzugefügt wird. Die alten Knoten bleiben jeweils bestehen.
Es existieren bessere exakte Algorithmen. Diese kommen alle aus dem Gebiet der linearen Optimierung. Im allgemeinen Fall ist das Problem jedoch nicht effizient lösbar. Wir
sind genauer.
Folie 13
Satz 4 (Komplexität des Handlungsreisendenproblems). Es sei G = (V, E, fE ) ein
vollständiger, symmetrischer, metrischer gewichteter Graph. Für das Handlungsreisendenproblem gibt es keinen allgemeinen Algorithmus, welcher das Problem stets in polynomialer
Laufzeit löst.
Dies bedeutet, dass es kein Polynom p ∈ P gibt
p(x) = α0 + α1 x + · · · + αK xK
mit K ∈ N beliebig aber fest, so dass das Problem stets (also bei beliebig ungünstiger
Verteilung der Gewichte) im Aufwand
A(n) = O(p(n))
gelöst werden kann.
Das oben angesprochene triviale Verfahren hat nicht polynomielle Laufzeit, denn n! ist
kein Polynom in n.
8
3 Approximierung der Lösung
Es existieren verschiedene effiziente Verfahren, welche die Lösung des Handlungsreisendenproblems approximieren.
Folie 14
Ein einfaches heuristisches Vorgehen ergibt sich durch folgende Strategie:
• Wir starten in einem beliebigen Knoten, ohne Einschränkung x1 = 1.
• In jedem Schritt wählen wir als nächstes den Knoten mit minimalem Abstand
unter denjenigen, die wir noch nicht besucht haben.
• Zum Abschluss fügen wir die Kante zum Startknoten hinzu.
Satz 5 (Nächster-Nachbar). Der Nächste-Nachbar Algorithmus lässt sich in quadratischer Laufzeit
O(n2 )
umsetzen.
Beweis. Von x1 = 1 werden in n − 1 Schritten die weiteren Knoten hinzugefügt. Die Suche nach dem Minimum benötigt ohne Verwendung spezieller Datenstrukturen jeweils
n Operationen.
9
Herunterladen