2010-06-17 13 views
6

sto cercando di sviluppare un algoritmo che identifica tutti i possibili percorsi tra due nodi in un grafico, come in questo esempio:Tutte le possibili percorsi in un grafo ciclico

image.

infatti, ho solo bisogno di sapere quali nodi compaiono in tutti i percorsi esistenti.

nel web ha solo riferimenti su DFS, A * o dijkstra, ma penso che in questo caso non funzionino.

Qualcuno sa come risolverlo?

+1

Compiti? Cosa hai provato fino ad ora? – user85509

+2

non ci sarà un numero infinito di percorsi se il grafico è ciclico? – jalf

+1

@jalf, l'ho pensato anch'io, ma Wikipedia dice che c'è qualche disaccordo. "Un percorso senza vertici ripetuti è chiamato un percorso semplice, e un ciclo senza vertici o bordi ripetuti a parte la ripetizione necessaria del vertice di inizio e di fine è un semplice ciclo. Nella teoria dei grafi moderni, il più delle volte" semplice "è implicito cioè, "ciclo" significa "ciclo semplice" e "percorso" significa "percorso semplice", ma questa convenzione non è sempre osservata, specialmente nella teoria dei grafi applicata ". –

risposta

4

È possibile trovare tutti i percorsi utilizzando DFS come | Vlad descritto. Per trovare quali nodi compaiono in ogni percorso, puoi semplicemente mantenere una matrice di booleani che dice se ogni nodo è apparso in ogni percorso fino a quel momento. Quando il DFS trova un percorso, passare attraverso ogni vertice non nel percorso e impostare il valore dell'array corrispondente su falso. Quando hai finito, solo i vertici con valori di true saranno quelli che appaiono in ogni percorso.

Pseudocodice:

int source; 
int sink; 
int nVerts; 
bool inAllPaths[nVerts]; // init to all true 
bool visited[nVerts]; // init to all false 
stack<int> path; // init empty 

bool dfs(int u) 
    if (visited[u]) 
    return; 
    if (u == sink) 
    for i = 0 to nVerts-1 
     if !stack.contains(i) 
     inAllPaths[i] = false; 
    return true; 
    else 
    visited[u] = true; 
    stack.push(u); 
    foreach edge (u, v) 
     dfs(v); 
    stack.pop(); 
    visited[u] = false; 
    return false; 


main() 
    dfs(source); 
    // inAllPaths contains true at vertices that exist in all paths 
    // from source to sink. 

Tuttavia, questo algoritmo non è molto efficiente. Ad esempio, in un grafico completo di n vertici (tutti i vertici hanno contorni a tutti gli altri) il numero di percorsi sarà n! (n factorial).

Un algoritmo migliore sarebbe quello di verificare l'esistenza in ogni percorso di ogni vertice separatamente. Per ogni vertice, cerca di trovare un percorso dalla sorgente al sink senza andare in quel vertice. Se non riesci a trovarne uno, è perché il vertice appare in ogni percorso.

Pseudocodice:

// Using the same initialisation as above, but with a slight modification 
// to dfs: change the foreach loop to 
foreach edge (u, v) 
    if (dfs(v)) 
    return true; // exit as soon as we find a path 

main() 
    for i = 0 to nVerts-1 
    set all visited to false; 
    if (inAllPaths[i]) 
     visited[i] = true; 
     if (dfs(source)) 
     inAllPaths[i] = false; 
     visited[i] = false; 

Purtroppo, questo ha ancora caso peggiore esponenziale durante la ricerca di un percorso. Puoi sistemarlo cambiando la ricerca in una ricerca in ampiezza. Se non sbaglio, questo dovrebbe darti prestazioni O (VE).

1

Esegui DFS dal nodo iniziale e mantieni il tuo stack che ti dice quali nodi hai visto in un dato momento. Prenditi cura dei cicli: quando hai visto un nodo due volte, hai un ciclo e devi interrompere il percorso corrente. Fare attenzione a non visitare il genitore di un nodo, in modo da evitare cicli di lunghezza 1 (aggiungere un parametro parent alla funzione DFS, sarà di aiuto).

Quindi, quando si raggiunge il nodo di destinazione, restituire il contenuto del proprio stack.

Al termine di DFS, si avranno tutti i percorsi.

1

Per questo problema, per prima cosa vorrei ottenere l'albero t formato da un DFS su uno dei nodi di destinazione u. Poi, colore tutti i nodi, consente di dire blu, che sono nella sottostruttura s radicata al vostro secondo nodo di destinazione v.

For each node k in subtree s, 
    if k has an edge to a non-blue node x 
    then k is true and x is true. 

Inoltre, Mark V come vero. Infine, userei una funzione ricorsiva fino alle foglie. Qualcosa come

function(node n){ 
    if(n = null) 
     return false 
    if(function(n.left) or function(n.right) or n.val){ 
     n.val = true 
     return true 
    } 
    else 
     return false 
} 

Tutti i nodi contrassegnati come veri sarebbero i tuoi nodi nei percorsi da u a v.Runtime sarebbe al massimo (Vertices + Edges) poiché DFS = (V + E) il massimo per loop (V) il ricorsivo al massimo (V)

0

un vertice è su un percorso da A a B se è raggiungibile da A e B è raggiungibile da esso.

Quindi: eseguire un riempimento a partire da A. Contrassegnare tutti i vertici. eseguire un riempimento a pieno riempimento partendo da B e seguendo i bordi al contrario. Tutti i vertici contrassegnati che incontri sono parte della soluzione.

1

So che è passato un po 'di tempo, ma sono venuto qui cercando un algoritmo per trovare All Paths (non solo il percorso più breve) in SQL o Java e ho trovato questo tre (li ho appena postati per mantenere i concetti organizzati):

Se si inseriscono nei commenti le righe start with n1... e where n2..., la query restituirà tutti i percorsi in tutto il grafico.

Problemi correlati