Estratto del documento

Seleziona un arco di costo minimo e coloralo di blu.

Regola del Ciclo

Scegli un ciclo semplice in modo che non contenga archi rossi. Tra tutti gli archi non colorati del ciclo, seleziona un arco di costo massimo e coloralo di rosso.

Teorema(1): sia un grafo non orientato, connesso e pesato sugli archi. Ogni passo di colorazione del metodo goloso mantiene la seguente invariante: "Esiste sempre un minimo albero ricoprente che contiene tutti gli archi blu e che non contiene nessun arco rosso". Inoltre, il metodo goloso colora tutti gli archi di G.

Algoritmo di Prim

L'algoritmo di Prim è un algoritmo greedy che permette il calcolo del minimo albero ricoprente di un grafo. Supposto di avere un solo vertice di G colorato di blu, scelto arbitrariamente, si può far convergere l'albero colorato al minimo albero ricoprente di G(n - 1) applicando volte l'algoritmo di Prim consistente nel seguente passo:

Scegli un arco di costo minimo incidente

sull'albero blu T e coloralo di blu. Una volta fatto ciò l'algoritmo di Prim restituisce l'albero blu calcolato che è proprio il minimo albero ricoprente.

Pseudocodice:

Teoria dei Grafi 9
Una sua implementazione in java:
public List<Double> prim(){
    int nodoPartenza=0;
    Double[] distanze=new Double[n];
    for(int i=0;i<n;i++)
        distanze[i]=Double.POSITIVE_INFINITY;
    boolean[] raggiunti=new boolean[n];
    for(int i=0;i<n;i++)
        raggiunti[i]=false;
    int[] padri = new int[n()];
    distanze[nodoPartenza]=0.0;
    padri[0]=0;
    int nodoCorrente=nodoPartenza;
    while(nodoCorrente!=-1){
        raggiunti[nodoCorrente]=true;
        Iterator<A> adnn=adiacenti(nodoCorrente);
        while(adnn.hasNext()){
            A a=adnn.next();
            if(!raggiunti[a.getFin()]){
                double nuovaDist=pesoArco(a);
                if(nuovaDist<distanze[a.getFin()]){
                    distanze[a.getFin()]=nuovaDist;
                    padri[a.getFin()]=nodoCorrente;
                }
            }
        }
        nodoCorrente=-1;
        double minPeso=Double.POSITIVE_INFINITY;
        for(int i=0;i<n;i++)
            if(!raggiunti[i] && distanze[i]<minPeso){

Teorema: l'algoritmo di Prim calcola correttamente un minimo albero ricoprente.

Dimostrazione: sfruttando il teorema(1) è sufficiente dimostrare che il generico passo dell'algoritmo di Prim è una applicazione della regola del taglio. Infatti, sia l'albero blu T prima del generico passo. L'algoritmo fino ad ora ha colorato di blu tutti e soli gli archi di T. Considerando il taglio che separa T dal resto del grafo: l'arco scelto dal passo di Prim è esattamente l'arco dal costo minimo in tale taglio per cui risulta una colorazione in base alla regola del taglio.

Foresta: è un grafo non orientato nel quale due vertici qualsiasi sono connessi al più da un cammino. Una foresta risulta costituita da una unione disgiunta di alberi che costituiscono le componenti connesse massimali del grafo.

Algoritmo di Kruskal

L'algoritmo di Kruskal è

Un algoritmo greedy per il calcolo del minimo albero ricoprente per un grafo. Nell'algoritmo di Kruskal gli archi blu costituiscono una foresta di alberi. Durante la sua esecuzione, l'algoritmo di Kruskal mantiene la foresta di alberi blu, inizialmente costituita da alberi disgiunti ciascuno dei quali composto da un solo nodo. Per ciascun arco del grafo si applica il passo:

  1. Se l'arco ha entrambi gli estremi nello stesso albero blu, coloralo di rosso.
  2. Altrimenti coloralo di blu.

Quando l'algoritmo avrà esaminato tutti gli archi del grafo restituirà l'albero formato dagli archi blu.

Pseudocodice:


public Grafo<ArcoPesato> kruskal(){ // theta( m n) || (union find) theta(m lg n)
    ArcoPesato[] archi = generaArchiOrdinati(); // theta(m lg n) || theta(n^2 + m lg n)
    int inseriti = 0;
    GrafoLista<ArcoPesato> albero = new GrafoLista<ArcoPesato>(n());// creare union find - theta(n)//theta (m + n lg n)
    for(int i=0; i < archi.length; i++){
        if(inseriti == n()-1) break;
        ArcoPesato arco = archi[i];
        int u = arco.getNodoU();
        int v = arco.getNodoV();
        if(!albero.connessi(u, v)){
            albero.aggiungiArco(arco);
            albero.union(u, v);
            inseriti++;
        }
    }
    return albero;
}

Una sua implementazione in java:


public class GrafoLista<T> implements Grafo<T> {
    private int n;
    private List<List<Arco<T>>> adiacenze;
    
    public GrafoLista(int n){
        this.n = n;
        adiacenze = new ArrayList<>();
        for(int i=0; i < n; i++){
            adiacenze.add(new ArrayList<>());
        }
    }
    
    public void aggiungiArco(Arco<T> arco){
        int u = arco.getNodoU();
        int v = arco.getNodoV();
        adiacenze.get(u).add(arco);
        adiacenze.get(v).add(arco);
    }
    
    public boolean connessi(int u, int v){
        for(Arco<T> arco : adiacenze.get(u)){
            if(arco.getNodoU() == v || arco.getNodoV() == v){
                return true;
            }
        }
        return false;
    }
    
    public void union(int u, int v){
        // implementazione dell'union find
    }
    
    // altre implementazioni dei metodi dell'interfaccia Grafo
}

(i<archi.length)&& (inseriti<n()-1); i++){ // m volte
    <List<Integer> lista = albero.depthFirstSearch(archi[i].getIn()); // theta(n) || theta (n^2)
    if (!lista.contains(archi[i].getFin())){ // theta(1)
        albero.aggiungiArco(archi[i]); // theta(1)
        inseriti++; // theta(1)
    }
}
if (inseriti==n()-1)
    return albero;
return null;

Teorema : L'algoritmo di Kruskal calcola correttamente un minimo albero ricoprente.

Dimostrazione : in base al teorema(1) è sufficiente dimostrare che l'algoritmo di Kruskal è una applicazione del metodo goloso. Ricordando che gli archi vengono esaminati in ordine non decrescente, quando l'algoritmo di Kruskal esamina l'arco esso non è stato ancora colorato mentre tutti gli archi di tale che sono stati già colorati. Sie G costo(e costo(e)ha che:

Se l'arco ha entrambi gli estremi nello stesso albero blu, allora induce un ciclo in tale e albero blu: tale ciclo

non contiene archi rossi ed è l'arco di costo massimo in tale ciclo. Allora l'algoritmo colora di rosso tale arco in base alla regola del ciclo. Se l'arco ha gli estremi in due diversi alberi, allora attraversa un taglio che separa tali alberi. Osserviamo che è il primo arco che attraversa tale taglio ad essere considerato dall'algoritmo: è quindi l'arco di costo minimo in un taglio che non contiene archi blu e l'algoritmo di Kruskal colora correttamente di blu in base alla regola del taglio.

Cammino minimo= (N,Definizione : Sia un grafo orientato pesato sugli archi, dove la funzione di G E, λ): →peso è tale che . Un cammino (di costo) minimo fra una coppia di vertici λ E R x y* connessi in è un cammino che ha un costo minore o uguale a quello di ogni altro G πx,y cammino tra gli stessi vertici, cioè tale che πx,y * ) = min )λ(π λ(πx,yx,y ⊆Gπ

x,yE la distanza tra i due nodi è propriod x, y * = )d(x, y) λ(πx,yCammino minimo in grafi con ciclo ∀e ∈ → ≥ 0Nel caso di un grafo con cicli si assume che . Questo si ha perché seE λ(e)si avessero archi con peso negativo all'interno di un ciclo si otterrebbe un cammino che,-∞virtualmente, avrebbe costo .Esistena cammini minimi semplici R= (V , : →Sia un grafp orientato con funzione costo . Se non ci sono cicliG E) ω Enegativi, fra ogni coppia di vertici connessi di G esiste sempre un cammino minimosemplice,in cui cioè tutti i nodi sono distinti.Albero dei cammini minimi = (N,Definizione : Sia un grafo non orientato pesato sugli archi posto un nodo diG E, λ)∈ = (N , , )radicamento si definisce un albero ricoprente di , tale che:s N G A E λs A A∀u ∈ , = = 0) → (s, = (s,N u s(s d e) d u) s A GTecnica del rilassamentoLa tecnica del rilassamento consiste

Nell'associare ad ogni vertice un attributo d(s, v) chiamata stima di cammino minimo che costituisce un limite superiore al peso di cammino minimo tra il nodo s e la radice. Tale stima sarà man mano diminuita ripetutamente fino a convergere con il reale peso del cammino minimo tra s e v.

GLi attributi sono inizializzati a −∞.

Pseudocodice:

Algoritmo di Dijkstra

L'algoritmo di Dijkstra è un algoritmo di calcolo di un albero di cammini minimi per un grafo G = (N, E, λ) dove la funzione costo è definita. Sia T un albero di cammini minimi radicato nel nodo s, ma tale che non includa tutti i vertici raggiungibili da s. Allora l'arco con costo minimo (v, u) che minimizza la quantità d(s, v) + λ(v, u) appartiene a un cammino minimo da s a u.

Dimostrazione: Supposto per assurdo che l'arco non appartenga a un cammino minimo.

da a, e che quindi a è raggiungibile da s. Allora ci deve essere un cammino π da s a a con costo minimo che non passa per v. Sia T l'albero dei cammini minimi da s a tutti i nodi v in V. Poiché a è raggiungibile da s, allora ci deve essere un arco con costo minimo da s a v in T. Sia x il nodo precedente a v in T. Allora il sotto-cammino di π da s a x e il sotto-cammino di π da x a a sono cammini minimi. Poiché T è un albero dei cammini minimi, anche i due sotto-cammini saranno cammini minimi. Quindi, ho che d(s, v) + λ(π) = d(s, x) + λ(x, a). Graficamente la situazione descritta sarà: Da ciò si ha: d(s, v) + λ(π) = d(s, x) + λ(x, a) = d(s, v) + λ(π) + λ(π) = d(s, x) + λ(x, a) + λ(π) = d(s, v) + λ(π) + λ(π) = d(s, x) + λ(x, a) + λ(π) + λ(π) Poiché λ(π) + λ(π) minimizza d(s, v) + λ(π), allora deve valere: d(s, v) + λ(π) + λ(π) ≥ d(s, x) + λ(x, a) + λ(π) + λ(π)
x) λ(x, y) d(s, u) λ(u, v)e allora ∗ ∗= + + ) ≥ + + )d(s, v) d(s, x) λ(x, y) λ(π d(s, u) λ(u, v) λ(πyv yvTeoria dei Grafi 13∗ ) ≥ 0Infine, poichè gli archi sono non negativi ho . Questo ci porta allaλ(πyvcontraddizione: □∗= ) ≥ + >d(s, v) λ(π d(s, u) λ(u, v) d(s, v)svDetto ciò Dijkstra per calcolare l'albero dei cammini del grafo , posto che abbia nodi,G G n(n − 1)applica volte il seguente passo:Segli un arco con e che minimizza(u, ∈ ) ∈ )/v) u N(T v N(Teffettua il rilassamento+ = +d(s, u) λ(u, v), d(s, v) d(s, u) λ(u, v),e aggiungilo a T.Pseudocodice:Implementazione:public List<Double> dijkstra(int nodoPartenza){ Double[] distanze=new Double[n];for(int i=0;i<n;i++)distanze[i]=Double.POSITIVE_INFINITY;boolean[] raggiunti=new boolean[n];for(int i=0;i<n;i++)raggiunti[i]=false;distanze[nodoPartenza]=0.0;int
Anteprima
Vedrai una selezione di 5 pagine su 17
Teoria dei Grafi Pag. 1 Teoria dei Grafi Pag. 2
Anteprima di 5 pagg. su 17.
Scarica il documento per vederlo tutto.
Teoria dei Grafi Pag. 6
Anteprima di 5 pagg. su 17.
Scarica il documento per vederlo tutto.
Teoria dei Grafi Pag. 11
Anteprima di 5 pagg. su 17.
Scarica il documento per vederlo tutto.
Teoria dei Grafi Pag. 16
1 su 17
D/illustrazione/soddisfatti o rimborsati
Acquista con carta o PayPal
Scarica i documenti tutte le volte che vuoi
Dettagli
SSD
Scienze matematiche e informatiche MAT/02 Algebra

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher AlienSK00 di informazioni apprese con la frequenza delle lezioni di Algoritmi e strutture dati e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università della Calabria o del prof Flesca Sergio.
Appunti correlati Invia appunti e guadagna

Domande e risposte

Hai bisogno di aiuto?
Chiedi alla community