La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

Algoritmi greedy Gli algoritmi greedy in genere non sono esatti, cioè determinano soluzioni non necessariamente ottime Per il problema dell’albero ricoprente.

Presentazioni simili


Presentazione sul tema: "Algoritmi greedy Gli algoritmi greedy in genere non sono esatti, cioè determinano soluzioni non necessariamente ottime Per il problema dell’albero ricoprente."— Transcript della presentazione:

1 Algoritmi greedy Gli algoritmi greedy in genere non sono esatti, cioè determinano soluzioni non necessariamente ottime Per il problema dell’albero ricoprente sono esatti Algoritmo di Prim conserva connessione e aciclicità tende alla ricopertura Algoritmo di Kruskal conserva aciclicità e ricopertura tende verso la connessione

2 Algoritmo di Prim Prim(G,c) U = {v1}; X =  While U  V do e* = (u,v) = arg minu U, v V\U cuv X = X  {e*} U = U  {v} Parte con un solo vertice (arbitrario) e nessun arco (sottografo connesso e aciclico, ma non ricoprente) Aggiunge ogni volta l’arco minimo del taglio individuato dall’albero corrente  conserva connessione e aciclicità

3 Esempio di esecuzione dell’algoritmo di Prim
U = {v1} X =Ø 1 v1 v5 v2 v3 v4 2 6 5 3 4 1 v1 v5 v2 v3 v4 2 6 5 3 4 v4 1 v1 v5 v2 v3 2 6 5 3 4 U = {v1, v2, v5} X = {[v1,v2], [v1,v5]} U = {v1, v2} X = {[v1,v2]} 1 v1 v5 v2 v3 v4 2 6 5 3 4

4 Esempio di esecuzione dell’algoritmo di Prim
1 v1 v5 v2 v3 v4 2 6 5 3 4 U = {v1, v2 , v3, v5} X = {[v1,v2], [v1,v5], [v3,v5]} costo: 9 1 v1 v5 v2 v3 v4 2 6 5 3 4 U = {v1, v2 , v3 , v4, v5} = V X = {[v1,v2], [v1,v5], [v3,v5], [v4,v5]}

5 Esempio di esecuzione dell’algoritmo di Prim
Altre soluzioni ammissibili (di costo non inferiore) costo: 11 1 v1 v2 1 v1 v5 v2 v3 v4 2 6 5 3 4 4 costo: 16 2 3 2 6 2 v5 v3 4 5 v4 1 v1 v5 v2 v3 v4 2 6 5 3 4 Altra soluzione ottima, ottenibile cambiando lato al passo 2 costo: 9

6 Complessità dell’algoritmo di Prim
La complessità dipende da come si determina e* Idea 1: scandire tutti i lati : O(mn) Ogni ciclo While richiede O(m) operazioni elementari (se T(U,X) è una lista di lati più un vettore di incidenza 4m + 4 operazioni) 4 per aggiornare X e U (incremento contatore, aggiunta estremi nella lista, cambio di bit nel vettore) 2m per l’appartenenza al taglio [v,w]   (S), [v,w]  A 2m per confrontare il costo minimo con cuv ed eventualmente aggiornarlo

7 Una versione O(n2) Pred[v] = arg min uU cuv
N.B.: Ad ogni passo nel taglio cambiano solo gli archi incidenti nell’ultimo vertice aggiunto a U Idea 2: per ogni vertice v fuori da U conservare il lato minimo incidente in v del taglio indotto da U (e il suo costo) Pred[v] = arg min uU cuv Cmin[v] = min uU cuv (cuv = + se [i,j] E) 4 vU v1 2 v3 Pred[v] = v3 6 Cmin[v] = 2 v5 U

8 Una versione O(n2) Prim2(G,c) For v = 1 to n do Uinc[v] = Cmin[v] = + Pred[v] = 0 { U = {v1}; X =  } Uinc[1] = 1 Cmin[1] = 0 For v  Adj(1) do Cmin[v] = c1v Pred[v] = 1 m = 0 … While m < n-1 do {U  V} vMin = min = + For v = 2 to n do If (Uinc[v] = 0) and (Cmin[v] < min) min = Cmin[v] vMin = v Uinc[vMin] = 1 {U = U  {v}} For v  Adj(vMin) do If (Uinc[v] = 0) and (cvvMin<Cmin[v]) Cmin[v] = cvvMin Pred[v] = vMin

9 Esecuzione della versione O(n2)
1 v1 v5 v2 v3 v4 2 6 5 3 4 Prim2(G,c) For v = 1 to n do Uinc[v] = Cmin[v] = + Pred[v] = 0 { U = {v1}; X =  } Uinc[1] = 1 Cmin[1] = 0 For v  Adj(1) do Cmin[v] = c1v Pred[v] = 1 m = 0 U = {v1} X = Ø 1 1 v1 v2 Uinc = [ ] Cmin = [ ] Pred = [ ] 4 2 3 2 6 v5 2 v3 4 5 v4

10 Esecuzione della versione O(n2)
1 v2 U = {v1,v2} X = {[v1,v2]} U = {v1} … While m < n-1 do {U  V} vMin = min = + For v = 2 to n do If (Uinc[v] = 0) and (Cmin[v] < min) min = Cmin[v] vMin = v Uinc[vMin] = 1 {U = U  {v}} For v  Adj(vMin) do If (Uinc[v] = 0) and (cuv < Cmin[v]) Cmin[v] = cuv Pred[v] = vMin X = Ø v3 1 v1 v5 v2 v4 2 6 5 3 4 Uinc = [ ] Cmin = [ ] Pred = [ ]

11 Esecuzione della versione O(n2)
U = {v1, v2, v5} … While m < n-1 do {U  V} vMin = min = + For v = 2 to n do If (Uinc[v] = 0) and (Cmin[v] < min) min = Cmin[v] vMin = v Uinc[vMin] = 1 {U = U  {v}} For v  Adj(vMin) do If (Uinc[v] = 0) and (cuv < Cmin[v]) Cmin[v] = cuv Pred[v] = vMin X = {[v1,v2], [v1,v5]} v4 1 v1 v5 v2 v3 2 6 5 3 4 Uinc = [ ] Cmin = [ ] Pred = [ ]

12 Esecuzione della versione O(n2)
U = {v1, v2 , v3, v5} X = {[v1,v2], [v1,v5], [v3,v5]} … While m < n-1 do {U  V} vMin = min = + For v = 2 to n do If (Uinc[v] = 0) and (Cmin[v] < min) min = Cmin[v] vMin = v Uinc[vMin] = 1 {U = U  {v}} For v  Adj(vMin) do If (Uinc[v] = 0) and (cuv < Cmin[v]) Cmin[v] = cuv Pred[v] = vMin 1 v1 v2 4 2 3 2 6 v5 2 v3 4 v4 5 Uinc = [ ] Cmin = [ ] Pred = [ ]

13 Esecuzione della versione O(n2)
U = {v1, v2 , v3 , v4, v5} … While m < n-1 do {U  V} vMin = min = + For v = 2 to n do If (Uinc[v] = 0) and (Cmin[v] < min) min = Cmin[v] vMin = v Uinc[vMin] = 1 {U = U  {v}} For v  Adj(vMin) do If (Uinc[v] = 0) and (cuv < Cmin[v]) Cmin[v] = cuv Pred[v] = vMin X = {[v1,v2], [v1,v5], [v3,v5], [v4,v5]} 1 v1 v2 4 2 3 2 6 2 v5 v3 4 5 v4 Uinc = [ ] Cmin = [ ] Pred = [ ]

14 Complessità – Prim versione O(n2)
For v = 1 to n do … For v  Adj(1) do … While m < n-1 do … For v = 2 to n do … For v  Adj(vMin) do … 1 L’inizializzazione richiede O(n) 1 Il primo ciclo For interno richiede O(n) 2 3 Il secondo ciclo For interno scorre la stella uscente da vMin L’analisi aggregata dà O(m) per l’insieme delle sue esecuzioni 4 2 3 4 I due cicli For interni sono eseguiti n - 1 volte O(n2)

15 Una versione O(m log n) L’operazione più costosa è la ricerca del lato di costo minimo Idea 3: conserviamo gli O(n) lati candidati in uno heap creiamo lo heap dei lati candidati (BuildHeap): O(n) in più leggiamo direttamente l’elemento minimo: O(n) anziché O(n2) Aggiorniamo lo heap quando l’albero cresce di un vertice v; ogni lato incidente in v potrebbe entrare nello heap che andrebbe quindi aggiornato (Heapify): O(log n) anziché O(1) Complessivamente, esaminiamo O(m) archi

16 Correttezza dell’algoritmo di Prim
Dato un albero ricoprente T, lato di diminuzione è un lato e  T che, aggiunto a T, vi induce un ciclo C  T  {e} contenente un lato f  C \ {e} di costo superiore (ce < cf ) f ce < cf T e C c(T  {e}\{f}) < c(T) Se esiste un lato e di diminuzione rispetto a un albero T ricoprente, si può ridurre il costo di T scambiando il lato e con almeno un lato f di C

17 Correttezza dell’algoritmo di Prim
Per assurdo: l’albero T(V,X) restituito dall’algoritmo di Prim non sia ottimo, e lo sia invece T*(V,X*) Seguiamo l’esecuzione di Prim, arrestandoci al primo arco e  X, ma  X* Aggiungendo e a X*  ciclo C U Sia f  (U)  C Sicuramente ce  cf T* v h e Se ce = cf allora T*  {e} / {f} è ottimo perché costa come T* f Se ce < cf, e è un lato di diminuzione quindi T* non è ottimo!


Scaricare ppt "Algoritmi greedy Gli algoritmi greedy in genere non sono esatti, cioè determinano soluzioni non necessariamente ottime Per il problema dell’albero ricoprente."

Presentazioni simili


Annunci Google