Note della lezione 3

Transcript

Note della lezione 3
Algoritmi e Strutture Dati II: Parte B
Anno Accademico 2004-2005
Lezione 3
Docente: Ugo Vaccaro
In questa lezione deriveremo algoritmi di approssimazione per alcuni classici problemi su
grafi pesati. Iniziamo con il considerare il seguente problema
Steiner Tree
• Input:
– grafo G = (V, E)
– funzione peso w : E → R+ sugli archi
– sottoinsieme R ⊆ V
• Output: sottoalbero di G di minimo costo totale che copra tutti i vertici di R, dove
il costo dell’albero è definito come la somma dei costi dei suoi archi.
Ci sono delle similitudini tra questo problema e quello di determinare lo spanning tree di
peso minimo in un grafo. Infatti, se R = V allora i due problemi coincidono esattamente.
Come conseguenza, il problema dello Steiner Tree è risolubile in tempo polinomiale nel caso
particolare che R = V . In generale, il problema dello Steiner Tree è N P -hard. Il seguente
esempio mostra in cosa il problema dello Steiner Tree differisce dal problema del Minimum
Spanning Tree . Consideriamo il grafo a sinistra nella figura di sotto, in cui solo i vertici
anneriti sono richiesti. La figura immediatamente a destra mostra un Minimum Spanning
Tree sui vertici richiesti, di costo totale pari a 4. All’estremità destra è invece mostrato un
albero di Steiner che fa uso anche di vertici non richiesti (nel caso in questione, quello centrale),
di costo totale pari a 3.
2
2
1
1
2
2
1
1
1
1
2
Quindi, includere dei nodi non necessariamente richiesti nell’albero può far abbassare il costo
della soluzione. Questo è in effetti il tratto che distingue il problema del Minimum Spanning
Tree dal problema dello Steiner Tree . Il fatto che nel problema dello Steiner Tree si
possano scegliere o meno nodi in V − R fa sı́ che l’insieme delle possibili soluzioni al problema
aumenti enormemente, rendendo difficile l’individuazione della soluzione ottima.
1
Passiamo ora a considerare il progetto di algoritmi di approssimazione per il problema dello
Steiner Tree . Per prima cosa, mostriamo che è sufficiente considerare istanze del problema
in cui il grafo G = (V, E) è un grafo completo, ed in esso vale la diseguaglianza triangolare,
ovvero
∀u, v, z ∈ E w(u, v) ≤ w(u, z) + w(z, v).
(1)
Piò precisamente, mostreremo che se siamo in grado di produrre un algoritmo di approssimazione
con fattore di approssimazione ρ per il problemo dello Steiner Tree in grafi completi in cui
vale la diseguaglianza triangolare, allora siamo anche in grado di produrre un algoritmo di
approssimazione con lo stesso fattore di approssimazione ρ in istanze arbitrarie del problema
dello Steiner Tree .
Procederemo come segue. Data una istanza I = (G, R, w) arbitraria del problema dello
Steiner Tree , dove G è un grafo, R è il sottoinsieme dei vertici richiesti, e w è la funzione
peso sugli archi di G, trasformiamo innanzitutto I in tempo polinomiale in una istanza I 0 =
(G0 , R, w0 ), dove G0 è un grafo completo sugli stessi vertici di G, l’insieme dei vertici R richiesto
è immutato, e la funzione peso w 0 sugli archi (u, v) di G0 è definita come
X
w0 (u, v) =
w(e),
e∈p(u,v)
dove p(u, v) è un cammino di peso totale minimo tra i vertici u e v nel grafo G.
Osserviamo ora che per ogni arco (u, v) ∈ G, vale che
w(u, v) ≥ w 0 (u, v).
(2)
Ciò è ovvio in quanto il costo dell’arco (u, v) in G 0 è pari al costo del cammino di minimo costo
tra u e v in G. Sia OP T (I) il costo della soluzione ottima in G, e sia OP T (I 0 ) il costo della
soluzione ottima in G0 . Come conseguenza della (2) otteniamo che
OP T (I) ≥ OP T (I 0 ).
(3)
Sia ora T 0 un albero di Steiner in G0 , di costo minimo OP T (I 0 ). Consideriamo il sottografo H
di G composto da tutti i cammini di G che corrispondono agli archi di T 0 . Ovviamente vale che
il costo totale di H (ovvero la somma dei costi degli archi di H) è esattamente pari al costo di
T 0 . Il sottografo H non è necessariamente un albero. Eliminando da H tutti gli archi che creano
cicli, otteniamo un sottoalbero A di G che copre tutti i vertici richiesti, di costo al più pari al
costo di T 0 (visto che abbiamo eliminato degli archi da T 0 per ottenere A). Daltra parte, per
definizione, il costo OP T (I) di un albero di Steiner di G è non superiore a A, pertanto otteniamo
OP T (I) ≤ costo(A) ≤ costo(T 0 ) = OP T (I 0 ).
(4)
Mettendo insieme la (3) e la (4) otteniamo che
OP T (I) = OP T (I 0 ).
(5)
Riassumendo, abbiamo fatto vedere che il costo di una soluzione ottima in un grafo arbitrario G
è uguale al costo di una soluzione ottima in un grafo completo G 0 facilmente ottenibile da G. Non
2
solo, abbiamo anche fatto vedere che data una soluzione ottima in G 0 , è semplice ottenere da essa
una soluzione ottima nell’istanza originale G. Di conseguenza, possiamo limitarci a progettare
algoritmi per il problema dello Steiner Tree in grafi completi, in cui valga la diseguaglianza
triangolare. L’algoritmo di approssimazione in tali grafi è molto semplice.
Algoritmo di approssimazione per Steiner Tree
1. Costruisci un Minimum Spanning Tree T sui vertici in R del grafo input G
2. Return T
Dimostriamo che l’algoritmo sopra esposto ha fattore di approssimazione pari a 2. Sia S uno
Steiner tree di costo minimo. Sostituiamo ogni arco (u, v) di S con la coppia di archi direzionati
(u, v) e (v, u) e si proceda ad una visita di tutti i nodi del grafo cosı́ ottenuto (si veda la figura
di sotto).
Il percorso relativo alla visita potrá passare per piú di una volta per uno stesso vertice, e
passerá sia attraverso vertici in R che attraverso vertici non in R (denotati con un circolo vuoto
nella figura di sopra). Il costo di questo percorso é pari a 2OP T , visto che usiamo ogni arco di
S esattamente due volte (una volta in un verso, e la seconda nell’altro verso). A questo punto,
usiamo la diseguaglianza triangolare per evitare di passare due volte attraverso uno stesso vertice
e per evitare di passare attraverso vertici non in R (si veda la figura di sotto).
Essenzialmente, stiamo qui usando il fatto che andare direttamente da un vertice u ad un
vertice v costa di meno che andarci passando attraverso un qualche vertice intermedio. In questo
modo otterremo un ciclo che attraversa tutti i vertici di R, di costo al piú 2OP T (a causa della
diseguaglianza triangolare). Eliminando un qualsiasi arco da questo ciclo ci dará un albero Z
che attraversa tutti e solo i vertici di R, di costo ancora inferiore, ovvero il costo di Z sará al
piú 2OP T . D’altra parte, il costo del Minimim Spanning Tree T (output del nostro algoritmo
di approssimazione) sará per definizione inferiore al costo dell’albero Z, che abbiamo prima
3
mostrato essere inferiore a 2OP T . Otteniamo quindi che la nostra soluzione al problema dello
Steiner Tree , ovvero un Minimum Spanning Tree su R, ha costo al piú 2OP T .
Possiamo mostrare che esistono classi di grafi in cui il costo di un Minimum Spanning Tree
é circa 2 volte il costo di uno Steiner Tree , quindi l’analisi della tecnica prima esposta non puó
essere essenzialmente migliorata. Consideriamo ad esempio il grafo completo G = (V, E), dove
V = {1, . . . , n, n + 1}, insieme richiesto R = {1, . . . , n}, e funzione peso sugli archi w : E → R +
cosı́ definita
1 se i = n + 1,
∀(i, j) ∈ E w(i, j) =
2 altrimenti.
Il costo della soluzione prodotta dal nostro algoritmo di approssimazione è pari al costo di un
MST su R, e quindi pari a 2(n − 1) D’altra parte, lo Steiner Tree di costo minimo è composto
da tutti gli archi dal nodo n + 1 (non richiesto) a tutti gli altri nodi del grafo. Tale Steiner Tree
ha costo totale pari a n, cioè circa la metá del costo di un MST su R.
Le tecniche appena sviluppate sono utili anche per la progettazione di algoritmi di approssimazione per il seguente importante problema: Problema del Commesso Viaggiatore
(TSP).
TSP
• Input:
– grafo G = (V, E)
– funzione costo c : E → R+ sugli archi
• Output: un ciclo di minimo costo totale che attraversa tutti i vertici di G una ed
una sola volta.
Il problema del TSP è NP-completo ed, in generale, è difficile da approssimare.
Teorema 1 Per ogni funzione ρ(n) calcolabile in tempo polinomiale, la esistenza di un algoritmo
di approssimazione con fattore di approssimazione ρ(n) per TSP implica che P = N P .
4
Dim. Proveremo che se esistesse un algoritmo di approssimazione con fattore di approssimazione
ρ(n) per TSP, allora sarebbe possibile decidere in tempo polinomiale se un grafo arbitrario G
possiede un ciclo Hamiltoniano,1 problema questo notoriamente N P -completo.
Sia a tale scopo G = (V, E) un grafo arbitrario, n = |V |. Trasformiamo G in una istanza di
TSP nel modo seguente. Sia G0 = (V, E 0 ) un grafo completo sullo stesso insieme dei vertici di
G. Inoltre, G0 ha una funzione costo c : E 0 → R+ sugli archi definita nel modo seguente:
∀(u, v) ∈ E 0
c(u, v) =
1,
C > nρ(n),
se (u, v) ∈ E,
se (u, v) ∈
/ E.
Supponiamo di avere un algoritmo di approssimazione A per il problema del TSP, con fattore
di approssimazione ρ(n). Sull’input G 0 l’algoritmo A produrrá una soluzione dal valore SOL.
Possono accadere due casi:
1. SOL < nρ(n). Sotto questa ipotesi, e per come è definito il grafo G 0 , possiamo dire che
l’algoritmo A ha trovato un ciclo che visita tutti i vertici di G 0 ed il ciclo è composto solo
da archi di costo 1. Ció implica, per come sono definiti i costi degli archi di G 0 , che il ciclo
trovato da A è composto solo da archi di G. Ovvero, possiamo concludere che G possiede
un ciclo Hamiltoniano.
2. SOL ≥ nρ(n). Sotto questa ipotesi, e per come è definito il grafo G 0 , possiamo dire che il
grafo G non possiede un ciclo Hamiltoniano. Infatti, se lo possedesse, vorrebbe dire che
la soluzione ottima del problema del TSP in G 0 ha valore pari a n, contraddicendo il fatto
che l’algoritmo A ha fattore di approssimazione pari a ρ(n).
In conclusione, la esistenza di un algoritmo di approssimazione con fattore di approssimazione
ρ(n) per TSP implica la esistenza di una procedura polinomiale per decidere se un grafo arbitrario ha un ciclo Hamiltoniano o meno, il che implicherebbe che P = N P a causa della
N P -completezza del problema del ciclo Hamiltoniano.
Nell’ ipotesi che la funzione costo sugli archi del grafo G soddisfi la diseguaglianza triangolare,
è abbastanza semplice produrre un algoritmo di approssimazione per il problema del TSP con
fattore di approssimazione 2. L’algoritmo è simile all’algoritmo di approssimazione per Steiner
Tree .
Algoritmo di approssimazione per TSP
1. Costruisci un Minimum Spanning Tree T del grafo input G
2. Sostituisci ogni arco (u, v) di T con la coppia di archi (u, v) e (v, u)
3. Costruisci un tour T del grafo cosı́ ottenuto, passando attraverso tutti i suoi archi
4. Output il ciclo C che visita i vertici di G nell’ordine della loro prima apparizione nel
tour T .
1
Si ricordi che un ciclo Hamiltoniano è un ciclo che attraversa tutti i vertici del grafo, una ed una sola volta.
5
Il seguente esempio illustra il funzionamento dell’algoritmo. L’albero di sotto è il Minimum
Spanning Tree costruito dall’algoritmo. Su di esso costruiamo il tour T rappresentato dagli
archi trattegiati, più o meno come si procedeva nel caso dello Steiner Tree .
Dopodichè, in accordo all’algoritmo, otteniamo un ciclo che enumera i vertici dell’albero in
accordo all’ordine in cui essi compaiono per la prima volta nel tour T . Per la diseguaglianza
triangolare, i percorsi che vanno da un vertice direttamente ad un altro senza passare per vertici
intermedi, sono di costo minore e quindi non aumentano il costo del ciclo C rispetto al costo del
tour T .
Proviamo ora che l’algoritmo ha fattore di approssimazione pari a 2. Osserviamo innazitutto
che
costo(M ST ) ≤ OP T.
(6)
Infatti, se dal ciclo di costo OP T togliamo un arco, otteniamo un alberto T 0 , di costo inferiore
6
al ciclo, ed in piú T 0 avrá sicuramente costo maggiore od al piú uguale a T , che è un MST.
Pertanto il costo SOL della soluzione prodotta dall’algoritmo di sopra sará:
SOL = costo(C)
≤ costo(T ) (a causa della diseguaglianza triangolare)
= 2costo(M ST ) (per costruzione)
≤ 2OP T (per la (6)),
il che prova che l’algoritmo ha un fattore di approssimazione pari a 2.
Ci poniamo ora il problema di elaborare un algoritmo per il problema del TSP con un
migliore fattore di approssimazione. A tale scopo, è utile comprendere meglio come abbiamo
ottenuto il semplice algoritmo con fattore di approssimazione pari a 2. Siamo partiti con uno
MST T del grafo G ed abbiamo ottenuto un tour che visita tutti gli archi di T , essenzialmente
raddoppiando gli archi di T . Ció ci costa 2 volte il costo di T . Da questo tour, abbiamo ottenuto
un ciclo in G prendendo delle ”scorciatoie” nel tour. A causa delle diseguaglianza triangolare,
queste scorciatoie non hanno aumentato il costo della soluzione. La prova si concludeva con
l’osservazione che 2·(costo di T ) è inferiore a 2·OP T . La chiave del miglioramento dell’algoritmo
prima esposto risiedeá nel fatto che sará possibile ottenere un tour che attraversa tutti i vertici di
G ad un costo inferiore a 2·(costo di T ). A tale scopo abbiamo bisogno di introdurre il concetto
di Tour Euleriano di un grafo.
Un Tour Euleriano di un grafo G consiste in un percorso nel grafo G con vertice di partenza
e vertice di arrivo coincidenti, e che attraversa tutti gli archi di G una ed una sola volta. La
similaritá di questo problema con quello del ciclo Hamiltoniano è solo apparente. Mentre infatti
il problema di stabilire se un grafo possiede o meno un ciclo Hamiltoniano è N P -completo,
stabilire se un grafo possiede un tour Euleriano è un problema risolubile in tempo polinomiale.
Possiamo infatti provare il seguente risultato.
Teorema 2 Il grafo G possiede un tour Euleriano se e solo se G non ha vertici di grado dispari.
Dim. Proviamo innazitutto che se G = (V, E) possiede vertici di grado dispari allora G non
ammette un tour Euleriano. Supponiamo quindi che G possieda un vertice x di grado dispari
e scegliamo x come ipotetico punto di partenza e di arrivo del tour Euleriano. Osserviamo che
ogni volta che con questo percorso usciamo da x e vi ritorniamo, usiamo due archi incidenti su
x. Non saremmo quindi in grado di visitare tutti gli archi incidenti su x una ed una sola volta
con un percorso che parte e ritorna in x, in quanto tali archi sono in numero dispari.
La prova che è possibile costruire un tour Euleriano di G se G ha solo vertici di grado pari
la si effettua per induzione sul numero di archi |E|. Se |E| = 1 non vi è nulla da provare.
Assumiamo il teorema vero per tutti i grafi con |E| ≤ k, per qualche k ≥ 1, e sia G un grafo
con |E| = k + 1. Prendiamo un arbitrario vertice x in G e scegliamolo come punto di partenza
ed iniziamo a visitare il grafo, con l’accortezza di non passare mai due volte su di uno stesso
arco. Poichè il grado di ogni vertice v è pari, ogni volta che entriamo in un vertice v ne possiamo
anche uscire. Poichè il grafo G finito, prima o poi ritorneremo nel vertice x. Se abbiamo visitato
7
tutti gli archi di G, allora abbiamo trovato il tour Euleriano che cercavamo. Altrimenti abbiamo
trovato solo un percorso che parte ed arriva in x e che ogni qualvolta è entrato in qualche vertice
v ne è anche uscito. In altre parole, questo percorso ha visitato, per ogni vertice v, un numero
pari di archi incidenti su v. Togliamo gli archi di tale percorso da G, rimane un grafo G 0 con
un numero di archi ≤ k, ed ogni vertice di G 0 ha ovviamente grado pari. Il grafo G 0 ammette
quindi un tour Euleriano per ipotesi induttiva. Il tour prima trovato congiunto al tour di G 0
formano ovviamente un tour che parte e arriva in x e che visita tutti gli archi di G una ed una
sola volta.
Diciamo che un grafo G è Euleriano se in G vi è un tour Euleriano. A questo punto dovrebbe
essere anche chiaro perchè raddoppiavamo tutti gli archi del Minimum Spanning Tree T nel
primo algoritmo di approssimazione per TSP prima di trovare un tour nel grafo: raddoppiando
tutti gli archi ottenevamo infatti un grafo con tutti i nodi di grado pari e quindi il tour Euleriano
esisteva sicuramente. Non è detto peró che questo sia il modo piú economico per ottenere da
T un grafo Euleriano. Anzi, in generale non lo è . Banalmente, se un nodo ha giá grado pari
in T non vi è alcuna necessitá di raddoppiare il suo grado. In virtú del teorema precedente,
sono solo i vertici di grado dispari che sono fonte di problemi. Questi problemi li possiamo far
scomparire aggiungendo un arco a ciaschedun nodo di grado dispari, ottenendo quindi un grafo
con tutti i vertici di grado pari in cui costruire un tour Euleriano e poi, usando le scorciatoie
e la diseguaglianza triangolare, ottenere un ciclo che attraversa tutti i vertici una ed una sola
volta.
Ricordiamo la seguente relazione, che abbiamo provato nella prima lezione:
X
deg(x) = 2|E|.
(7)
u∈V
Immediata conseguenza della (7) è che il numero di vertici in G che hanno grado dispari è
pari, visto che la quantitá al membro destro della (7) è pari. Pertanto, dato un generico grafo
G, per trasformare G in un grafo Euleriano basta individuare il sottoinsieme dei vertici V 0
di grado dispari, dividerlo in due sottoinsiemi disgiunti di cardinalitá |V 0 |/2 ciascheduno, ed
aggiungere un matching tra tali due sottoinsiemi. Abbiamo quindi il seguente nuovo algoritmo
di approssimazione per TSP.
Algoritmo di approssimazione per TSP – fattore di approssimazione 3/2
1. Costruisci un Minimum Spanning Tree T del grafo input G
2. Calcola un matching perfetto M di minimo costo sui vertici di grado dispari di T .
Aggiungi M a T per ottenere un grafo Euleriano
3. Costruisci un tour euleriano T del grafo ottenuto al passo precedente
4. Output il ciclo C che visita i vertici di G nell’ordine della loro prima apparizione nel
tour T .
8
Analizziamo il costo della soluzione prodotta dall’algoritmo. A causa della diseguaglianza
triangolare, il costo SOL della soluzione prodotta non sará superiore al costo del grafo Euleriano
ottenuto al passo 2 dell’algoritmo, ovvero
SOL ≤ costo(T ) + costo(M ).
Giá sappiamo che costo(T ) ≤ OP T , valutiamo quindi il costo di M . A tale scopo, effettuiamo le
seguenti osservazioni. Consideriamo la soluzione ottima al problema dello TSP, ovvero il ciclo C
che attraversa tutti i vertici del grafo con un costo totale OP T . Tale ciclo C attraverserá anche
tutti i vertici dell’insieme V 0 (composto dai vertici di grado dispari nel MST T usato nel passo
1 dell’algoritmo), in un qualche ordine. Numeriamo i vertici di V 0 con i numeri 1, 2, . . . , |V 0 |
secondo quest’ordine di attraversamento (si veda la figura di sotto).
1
2
3
4
|V’|
Ora, il ciclo C per andare dal vertice 1 al vertice 2 seguirá un certo percorso (rappresentato
dalla linea tratteggiata tra 1 e 2 nella figura di sopra) che, a causa della diseguaglianza triangolare, avrá un costo ≥ del costo dell’arco tra 1 e 2. Stesso discorso per il percorso che C effettuerá
per andare da 2 a 3, e cosı́ via. In conclusione, la somma dei costi dei percorsi del ciclo C tra i
vertici di {1, 2, . . .} = V 0 , comprensivo del ritorno al vertice 1 sará ≥ della somma dei costi degli
archi diretti tra i vertici {1, 2, . . .} = V 0 . Facendo attenzione, si puó comprendere che gli archi
tra i vertici di V 0 si possono decomporre in due matching disgiunti (nella figura di sopra sono
rappresentati con archi di differente spessore). Possiamo quindi dire che il costo OP T del ciclo
ottimo C sará ≥ della somma dei costi dei percorsi del ciclo C tra i vertici di {1, 2, . . .} = V 0
che, a sua volta, è ≥ del costo dei due matching tra i vertici di V 0 . Almeno uno dei due matching
avrá quindi costo ≤ OP T /2. A maggior ragione, il matching di costo minimo M aggiunto tra i
vertici di V 0 nel passo 2 dell’algoritmo avrá costo ≤ OP T /2. Riassumendo otteniamo
1
3
SOL ≤ costo(T ) + costo(M ) ≤ OP T + OP T ≤ OP T,
2
2
9
il che conclude (finalmente) l’analisi dell’algoritmo.
La seguente figura mostra che l’analisi dell’algoritmo non puó essere migliorata, ovvero esistono istanze di input su cui l’algoritmo produce effettivamente una soluzione di costo pari a
3/2OP T.
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
.......
n/2
Il Minimum Spanning Tree trovato al Passo 1 dell’algoritmo è rappresentato da archi di
maggior spessore. Notiamo che ha solo due vertici di grado dispari, pertanto il matching di
minimo peso che viene aggiunto tra di essi è dato dall’arco di peso bn/2c. Abbiamo quindi che
l’algoritmo produce un ciclo di peso totale
SOL = (n − 1) + bn/2c.
D’altra parte, è facile vedere che il ciclo ottimo nel grafo di sopra ha peso esattamente n. Da
cui segue che nel grafo di sopra il nostro algoritmo è forzato a produrre una soluzione di costo
3/2OP T .
10