Per risolvere questo problema è importante considerare come si vuole rappresentare il grafico. Nel tuo schizzo hai assegnato un peso sia ai nodi che ai bordi, ma sembra che il peso del bordo sia irrilevante. Una buona rappresentazione potrebbe essere una coppia di peso e una serie di vicini:
Node(weight: Int, name: String, neighbours: Set of Node)
Durante la creazione del grafico iniziale non orientato, si mantiene un dizionario di nodi con il loro nome.
Per ogni percorso nell'input, si cerca o si creano tutti i nodi nel dizionario. Quindi incrementare il peso di tutti i nodi e collegare i nodi su ciascuna coppia del grafico tra loro:
var nodes = path.split("-").map(s => dict.lookupOrCreate(s));
// increment the weight
for var node <- nodes { node.weight++ }
// add the connections
for var i <- (1 upto nodes.length) {
nodes[i ].neighbours.add(nodes[i-1]);
nodes[i-1].neighbours.add(nodes[i ]):
}
Ora abbiamo un grafo non diretto, non connesso con nodi ponderati:
2 6 3 1 2 1
b ↔ a ↔ c ↔ e d ↔ f
↖_____↗
Ora vorrai rimuovere i cicli. Il tuo esempio contiene il sottografo
e 1 I. a6 → e1 → c3 ↗ e1
/ \ ==> a6 III.
a 6 | II. a6 → c3 → e1 ↘ c3
'- c 3
Come puoi vedere, ci sono tre possibilità per eliminare questo ciclo partendo da a
. La terza possibilità è la più semplice da implementare.
Se vuoi uno degli altri ordini, dovrai fare test di raggiungibilità più costosi: per ogni due nodi figlio, salta (ma non segna come visto) uno di quei nodi figli se è raggiungibile dall'altro senza utilizzando un percorso che utilizza il nodo corrente.
Successivamente, vogliamo ottenere il nodo con il peso più alto. Questo è un ordinamento semplice.
var [..., highest] = dict.values.sortBy(n => n.weight);
Ora attraversiamo tutto il grafico a partire da quel nodo e costruiamo il DAG. Possiamo costruire un grafico completamente nuovo (preferibile) o rimuovere il nodo corrente dal set vicino. Se questo insieme contiene dei nodi che erano già stati visitati durante l'assemblaggio dei DAG, è stato rilevato un ciclo (che interrompiamo saltando quel nodo). I sottografi non raggiungibili saranno dimenticati, questo eliminerebbe la parte d-e
. Possiamo ovviare a questo eliminando eventuali nodi dal dizionario e creando DAG finché il dtt non è vuoto. Questo creerebbe una foresta.
var forest = collect until dict.isEmpty {
var [..., highest] = dict.values.sortBy(n => n.weight);
def recurse(node: Node): DagNode {
// remove current node from dict
dict.delete(node.name);
// remove seen childs – eliminates cycles
var childs = node.neighbours.filter(c => dict.contains(c.name));
// mark all new childs as seen
for var child <- childs { dict.delete(child.name) }
// return the DAG subgraph (here: tree) and recurse into each child
return DagNode(weight: node.weight,
name: node.name,
childs: childs.map(c => recurse(c)));
}
yield recurse(highest);
}
Questo dovrebbe creare la foresta
_a_ d
/ | \ |
b c e f