Esercitazione

In questa sezione vogliamo elaborare un progetto di esempio per esplorare alcune tra le più importanti funzioni di Rocs. L'obiettivo è quello di creare un grafo e uno script che illustrino un semplice algoritmo di approssimazione di fattore 2, per trattare un problema di copertura minima dei vertici. Questo problema può essere descritto come la ricerca del più piccolo sottoinsieme C di vertici in un grafo tale che ogni arco ha almeno un'estremità in C. Si tratta di un problema NP-completo e il nostro obiettivo è quello di trovare un'approssimazione di fattore 2 attraverso la computazione di una corrispondenza all'interno di un grafo dato.

Il nostro obiettivo è di visualizzare la corrispondenza tra l'accoppiamento e la copertura minima dei vertici. Per ottenere questo obiettivo dobbiamo specificare due tipi di archi, uno per mostrare gli archi accoppiati e l'altro per mostrare gli archi «ordinari»; dobbiamo specificare inoltre due tipi di nodi, che useremo per distinguere i nodi contenuti in C da quelli non contenuti in C.

Creazione del grafo

Per creare il grafo usiamo il generatore di grafi fornito da Rocs, che si trova in GrafoStrumentiGenera grafo. In questo modo selezioniamo un «grafo casuale» composto di 30 nodi, 90 archi, e con seme di generazione 1 (il seme determina la casualità del grafo; partendo dallo stesso seme si riproduce lo stesso grafo).

Creazione dei tipi di elementi

Usiamo Tipi di elementi per creare sia un secondo tipo di nodo sia di arco. Dobbiamo aprire la finestra delle proprietà di entrambi questi due nuovi tipi facendo clic sul rispettivo pulsante delle Proprietà per impostare gli ID a 2; dobbiamo anche cambiare il colore degli elementi di questi due nuovi tipi (per distinguerli da quelli predefiniti). Infine dobbiamo impostare tutti i tipi di archi come bidirezionali, e gli ID del tipo predefinito a 1.

L'algoritmo

Al minimo è necessario implementare l'algoritmo di approssimazione. Per farlo si utilizza la seguente implementazione:

for (var i=0; i < Document.nodes.length; i++) {
    Document.nodes[i].type = 1;
}
for (var i=0; i < Document.edges.length; i++) {
    Document.edges[i].type = 1;
}

var E = Document.edges(); // insieme degli archi non esaminati
var C = new Array();      // archi accoppiati
while (E.length 
> 0) {
    var e = E[0];         // prende il primo arco e={u,v}
    var u = e.from();
    var v = e.to();
    e.type = 2;           // imposta l'arco come arco accoppiato
    E.shift();            // elimina l'arco e (i.e., E[0]) dalla lista degli archi
    C.push(u);            // aggiunge u a C
    C.push(v);            // aggiunge v a C

    // segna u,v come nodi di C
    u.type = 2;
    v.type = 2;

    // rimuove da E tutti gli archi incidenti a u o v
    var adjacent = u.edges();
    for (var i=0; i < adjacent.length; i++) {
        var index = E.indexOf(adjacent[i]); // trova l'indice
        if (index != -1) {
            E.splice(index, 1); // elimina l'indice dopo averlo trovato
        }
    }
    var adjacent = v.edges();
    for (var i=0; i < adjacent.length; i++) {
        var index = E.indexOf(adjacent[i]); // trova l'indice
        if (index != -1) {
            E.splice(index, 1); // elimina l'indice dopo averlo trovato
        }
    }
}
Console.log("Vertex Cover contains " + C.length + " nodes.");

Eseguire l'algoritmo

L'algoritmo può essere eseguito facendo clic sul pulsante Esegui nel pannello di controllo dello script.