2012-05-23 4 views
9

Per trovare il percorso più lungo in un DAG, sono a conoscenza di 2 algoritmi: algo 1: fai un ordinamento topologico + usa la programmazione dinamica sul risultato del tipo ~ o ~ algo 2: enumera tutto i percorsi nel DAG utilizzando DFS e registra il più lungo. Sembra che enumerare tutti i percorsi con DFS abbia una complessità migliore di algo 1. È vero?Percorso più lungo in un DAG

+0

correlati a [CS.SE]: [Ricerca di percorsi più brevi e più lunghi tra due vertici in un DAG] (http://cs.stackexchange.com/q/11295/11177) – Palec

risposta

8

La seconda opzione non è corretta: DFS non esplora tutti i percorsi possibili, a meno che il grafico non sia un albero o una foresta e inizi dalle radici. Il secondo algoritmo che conosco è negare i pesi e trovare il percorso più breve, ma è leggermente più lento dello top sort + DP algorithm che hai elencato come # 1.

+0

OK, intendevo DFS con riavvio da qualsiasi vertice che non è stato visitato nei precedenti passaggi DFS. Questo esplorerà l'intero DAG. Non dovrebbe essere più veloce di Topo sort + DP? – Frank

+0

@Frank DFS con riavvio dai vertici che non sono stati visitati non esplorerà tutti i percorsi. Si consideri un grafico 'A-> B-> C'; si avvia DFS da B, si passa a C e si arresta; quindi ricomincia da A, vai a B e fermati di nuovo, perché hai già visitato C. Entrambi i percorsi trovati da DFS, 'B-C' e' A-B', sono di lunghezza 1; il percorso più lungo 'A-B-C' è di lunghezza 2. – dasblinkenlight

+0

Perché dovresti iniziare da B? Devi avviare il DFS da fonti. – Frank

3

enumerare tutti percorsi in un DAG utilizzando "DFS":

def enumerate_dag(g): 

    def enumerate_r(n, paths, visited, a_path = []): 
    a_path += [n] 
    visited[n] = 1 
    if not g[n]: 
     paths += [list(a_path)] 
    else: 
     for nn in g[n]: 
      enumerate_r(nn, paths, visited, list(a_path)) 

    paths, N = [], len(g) 
    visited = np.zeros((N), dtype='int32') 

    for root in range(N): 
    if visited[root]: continue 
    enumerate_r(root, paths, visited, []) 

    return paths 
+1

Hai provato a passare un grafico a doppio diamante a questo codice? Sembra che abbia una probabilità 50/50 di perdere il percorso più lungo. – dasblinkenlight

+0

Ho appena provato con: [[1,2], [3], [3], [4], [5,6], [7], [7], [8], [9], [ ]]. Ottengo 4 percorsi: [[0, 1, 3, 4, 5, 7, 8, 9], [0, 1, 3, 4, 6, 7, 8, 9], [0, 2, 3, 4 , 5, 7, 8, 9], [0, 2, 3, 4, 6, 7, 8, 9]], che credo sia la risposta corretta. Per quanto posso dire (da molti altri test), questo algoritmo enumera correttamente i percorsi in un DAG. Topo sort si basa su un uso molto simile di DFS. A condizione che si avvii/si riavvii da fonti, DFS esplorerà * tutti * i nodi raggiungibili da ciascuna sorgente, quindi il codice sopra * completamente * esplora il DAG, non viene perso alcun vertice. – Frank

+0

Ho frainteso l'uso di 'visited' nel tuo codice: lo hai impostato, ma non lo usi per decidere se continuare l'attraversamento. Questo non è ciò che viene chiamato [DFS] (http://en.wikipedia.org/wiki/Depth-first_search), perché DFS non visita i nodi che sono stati completamente esplorati. La più grande differenza tra DFS e il tuo codice è che il tuo codice è estremamente inefficiente. Prova a ripetere lo stesso modello di diamante cinquanta volte per vedere cosa intendo: il tuo programma esplorerà tutti i percorsi '2^50', e ci sono molti percorsi da esplorare. – dasblinkenlight

2

No DFS necessaria. Algoritmo: prende un DAG G. Ciascun arco contiene una variabile E

for each node with no predecessor : 
    for each of his leaving arcs, E=1. 
for each node whose predecessors have all been visited : 
    for each of his leaving arcs, E=max(E(entering arcs))+1. 

max_path è la più alta E entro bordi quando tutti i nodi sono stati elaborati.

+0

Questa è la risposta corretta; vedi https://en.wikipedia.org/wiki/Longest_path_problem#Acyclic_graphs_and_critical_paths –