Análise e Síntese de Algoritmos Caminhos Mais Curtos para Todos os Pares CLRS, Cap. 25 Contexto • Algoritmos Elementares em Grafos (CLR, Cap. 22) – BFS & DFS – Ordenação Topológica & SCCs • Árvores Abrangentes de Menor Custo (CLR, Cap. 23) – Algoritmos de Borůvka, Kruskal e Prim • Caminhos mais curtos com fonte única (CLR, Cap. 24) – Algoritmos de Dijkstra e Bellman-Ford • Caminhos mais curtos entre todos os pares (CLR, Cap. 25) – Solução Recursiva, Algoritmos de Floyd-Warshall e Johnson 2006/2007 Análise e Síntese de Algoritmos 2 1 Resumo • Caminhos Mais Curtos entre Todos os Pares (APSPs) – Definições – Soluções recursivas • Algoritmo de Floyd-Warshall – Fecho Transitivo – Algoritmo de Johnson 2006/2007 Análise e Síntese de Algoritmos 3 Caminhos Mais Curtos entre Todos os Pares (APSPs) — Observações • Encontrar caminhos mais curtos entre todos os pares de vértices • Se pesos não negativos – Utilizar algoritmo de Dijkstra, assumindo cada vértice como fonte: O(V E lg V) (que é O(V3 lg V) se grafo é denso) • Se pesos negativos – Utilizar algoritmo de Bellman-Ford, assumindo cada vértice como fonte: O(V2E) (que é O(V4) se grafo é denso) • Objectivo: Encontrar algoritmos mais eficientes 2006/2007 Análise e Síntese de Algoritmos 4 2 APSPs — Definições • Representação: utilização de matriz de adjacências • Pesos dos arcos: matriz (n x n) W = (wij) se i = j $0 ! w ij = #peso do arco (i, j) se i & j e (i, j)( E !' se i & j e (i, j)% E " • Representação dos caminhos mais curtos: matriz (n x n) D = (dij) – dij é o peso do caminho mais curto entre os vértices i e j • dij = δ(vi,vj) 2006/2007 Análise e Síntese de Algoritmos 5 APSPs — Definições • Representação de caminhos mais curtos – Matriz de predecessores ∏ = (πij) – πij: • NIL: se i = j ou não existe caminho de i para j • Caso contrário: predecessor de j num caminho mais curto de i para j – Sub-grafo de predecessores de G para i, Gπ, i = (Vπ, i, Eπ, i) V#,i = {j $ V : #ij " NIL}! {} i E #,i = {(#ij , j): j " V#,i ! {i}} • Sub-grafo induzido pela linha i de ∏ – Exemplo 2006/2007 Análise e Síntese de Algoritmos 6 3 APSPs — Solução Recursiva • Sub-caminhos de caminhos mais curtos são também caminhos mais curtos • Peso mínimo em caminho de vértice i para vértice j que contém não mais do que m arcos: d(ijm ) – Com m = 0, existe caminho de i para j se e só se i = j #0 se i = j dij(0 ) = " !% se i $ j – Para m ≥ 1, { } dij(m ) = min dij(m !1), min{dik(m !1) + w kj } = min{dik(m !1) + w kj } 1"k "n 1"k "n wjj = 0 2006/2007 Análise e Síntese de Algoritmos 7 APSPs — Solução Recursiva • Calcular sequência de matrizes D(1), …, D(n-1), onde – D(n-1) contém os pesos dos caminhos mais curtos – D(1) = W Extend-Shortest-Paths(D,W) n = rows[W] D’: matriz (n x n) for i = 1 to n for j = 1 to n dij' = ! for k = 1 to n dij' = min(dij' , dik + w kj ) return D’ • Complexidade: Θ(n3) p/ cada matriz; Total: Θ(n4) 2006/2007 Análise e Síntese de Algoritmos 8 4 APSPs — Solução Recursiva • Genericamente: calcular D(i) em função de D(i-1) (e de W) • Complexidade para cálculo de D(n): Θ(n4) • OBS: é possível melhorar complexidade reduzindo número de matrizes calculadas: Θ(n3lg n) – A cada iteração, calcular D(2i) em função de D(i) e de D(i) 2006/2007 Análise e Síntese de Algoritmos 9 APSPs — Algoritmo de Floyd-Warshall • Caracterização de um caminho mais curto – Vértices intermédios de caminho p = 〈v1,v2,…,vk〉, {v2,…,vk-1} • Considerar todos os caminhos entre i e j com vértices intermédios retirados do conjunto {1,…,k} e seja p um caminho mais curto (p é simples) – Se k não é vértice intermédio de p, então todos os vértices intermédios de p estão em {1,…,k-1} – Se k é vértice intermédio de p, então existem caminhos p1 e p2, respectivamente de i para k e de k para j com vértices intermédios em {1,…,k} • k não é vértice intermédio de p1 e de p2 • p1 e p2 com vértices intermédios em {1,…,k-1} 2006/2007 Análise e Síntese de Algoritmos 10 5 APSPs — Algoritmo de Floyd-Warshall p1 k i p2 j Vértices entre 1 e k-1 • Formulação se k = 0 #w ij dij(k ) = " (k %1) (k %1) (k %1) !min(dij , dik + dkj ) se k $ 1 Vértices entre 1ek 2006/2007 Análise e Síntese de Algoritmos 11 APSPs — Algoritmo de Floyd-Warshall Floyd-Warshall(W) n = rows[W] D(0) = W for k = 1 to n for i = 1 to n for j = 1 to n dij(k ) = min(dij(k !1), dik(k !1) + dkj(k !1) ) (n) return D • Complexidade: Θ(n3) • Exemplo 2006/2007 Análise e Síntese de Algoritmos 12 6 Fecho Transitivo de um Grafo Dirigido • Dado um grafo G = (V, E) dirigido, o fecho transitivo é definido por G* = (V, E*) tal que, E*={(i, j): existe caminho de i para j em G} • Algoritmo: – Atribuir a cada arco peso 1 e utilizar algoritmo de FloydWarshall • Se dij ≠ ∞, então (i, j) ∈ E* • Complexidade: Θ(n3) 2006/2007 Análise e Síntese de Algoritmos 13 Fecho Transitivo de um Grafo Dirigido • Outro algoritmo: – Substituir operações min e + por ∨ e ∧, respectivamente – Se existe caminho de i para j com todos os vértices intermédios em {1,2,…,k}, t ij(k ) = 1 – Caso contrário, t ij(k ) = 0 – Formulação: #0 se i & j e (i, j)% E t ij(0 ) = " !1 se i = j ou (i, j)$ E – Complexidade: Θ(n3) – Exemplo 2006/2007 t ij(k ) = t ij(k $1) # (t ik(k $1) " t kj(k $1) ) se k ! 1 (mas constantes menores) Análise e Síntese de Algoritmos 14 7 Fecho Transitivo de um Grafo Dirigido Transitive-Closure(G) n = |V[G]| for i = 1 to n for j = 1 to n if i = j or (i, j) ∈ E t ij(0 ) = 1 else t ij(0 ) = 0 for k = 1 to n for i = 1 to n for j = 1 to n t ij(k ) = t ij(k !1) # (t ik(k !1) " t kj(k !1) ) (n) return T 2006/2007 Análise e Síntese de Algoritmos 15 APSPs — Algoritmo de Johnson • Utiliza algoritmos de Dijkstra e de Bellman-Ford • Baseado em re-pesagem dos arcos – Se arcos com pesos não negativos, utilizar Dijkstra para cada vértice – Caso contrário, calcular novo conjunto de pesos não negativos w’, tal que • Um caminho mais curto de u para v com função w é também caminho mais curto com função w’ • Para cada arco (u, v) o peso w’(u, v) é não negativo 2006/2007 Análise e Síntese de Algoritmos 16 8 APSPs — Algoritmo de Johnson • Dado G = (V, E), com função de pesos w e de repesagem h: V → R, seja w’(u, v) = w(u, v) + h(u) - h(v) • Seja p = 〈v0,v1,…,vk 〉. Então w(p) = δ(v0 , vk) se e só se w’(p) = δ’(v0, vk) = δ(v0, vk) + h(v0) - h(vk ) – Existe ciclo negativo com w se e só se existe ciclo negativo com w’ w ' (p ) = w (p ) + h(v 0 ) ! h(v k ) w ' (p ) = k " w ' (v i!1, v i ) i =1 k = " (w (v i!1, v i )+ h(v i!1 )! h(v i )) i =1 k = " w (v i!1, v i )+ h(v 0 )! h(v k ) = w (p)+ h(v 0 )! h(v k ) i =1 2006/2007 Análise e Síntese de Algoritmos 17 APSPs — Algoritmo de Johnson w (p ) = !(v 0 , v k ) " w ' (p ) = !' (v 0 , v k ) Hipótese: existe pz, caminho mais curto de v0 para vk com w’ Então: w ' (p z ) < w ' (p ) w (p z ) + h(v 0 ) ! h(v k ) = w ' (p z ) < w ' (p ) = w (p ) + h(v 0 ) ! h(v k ) O que implica w (p z ) < w (p ) Mas p é caminho mais curto com w; contradição ! OBS: Para quaisquer caminhos p1, p2 entre v0 e vk, verifica-se w(p1) < w(p2) ⇔ w’(p1) < w’(p2) 2006/2007 Análise e Síntese de Algoritmos 18 9 APSPs — Algoritmo de Johnson w (p ) = !(v 0 , v k ) " w ' (p ) = !' (v 0 , v k ) Semelhante: Admitir pz como caminho mais curto de v0 para vk com w (ou considerar observação anterior) Existe ciclo negativo com w se e só se existe com w’ c = " v 0 , v 1,K, v k !; v 0 = v k ; w (c ) < 0 w ' (c ) = w (c ) + h(v 0 ) ! h(v k ) = w (c ) ∴Caminhos mais curtos e ciclos negativos inalteráveis com mudanças na função de pesos w’(u, v) = w(u, v) + h(u) - h(v) 2006/2007 Análise e Síntese de Algoritmos 19 APSPs — Algoritmo de Johnson • Dado G = (V, E), criar G’ = (V’,E’): – V’ = V ∪ { s } – E’ = E ∪ { (s, v) : v ∈ V } – w(s, v) = 0 (∀ v ∈ V, atingível a partir de s) • Com ciclos negativos: – Detectados com algoritmo de Bellman-Ford aplicado a G’ ! • Sem ciclos negativos: – Definir: – Dado que: – Verifica-se: 2006/2007 h(v) = δ(s, v) h(v) ≤ h(u) + w(u, v) w’(u, v) = w(u, v) + h(u) - h(v) ≥ 0 ! Análise e Síntese de Algoritmos 24.10 20 10 APSPs — Algoritmo de Johnson • Executar Dijkstra para todo o u ∈ V – Cálculo de δ’(u,v), para u ∈ V – Mas também, • δ’(u,v) = δ(u, v) + h(u) - h(v) • δ(u,v) = δ’(u, v) + h(v) - h(u) 2006/2007 Análise e Síntese de Algoritmos 21 APSPs — Algoritmo de Johnson Johnson(G) Representar G’ if Bellman-Ford(G’,w,s) = FALSE print “Indicar ciclo negativo” else atribuir h(v) = δ(s, v), calculado com Bellman-Ford calcular w’(u,v) = w(u,v) + h(u) - h(v) para cada arco (u,v) foreach v ∈ V[G] executar Dijkstra(G,w’,v); calcular δ’(u, v) duv = δ’(u, v) + h(v) - h(u) return D 2006/2007 Análise e Síntese de Algoritmos 22 11 APSPs — Algoritmo de Johnson • Complexidade: – Bellman-Ford: O(V E) – Executar Dijkstra para cada vértice: O(V (V + E) lg V) • Assumindo amontoado (heap) binário – Total: O(V (V + E) lg V) • Útil para grafos esparsos • Exemplo 2006/2007 Análise e Síntese de Algoritmos 23 Revisão • Caminhos Mais Curtos entre Todos os Pares (APSPs) – – – – – Definições Solução recursiva Algoritmo de Floyd-Warshall Fecho Transitivo Algoritmo de Johnson • A seguir: – Fluxos máximos em grafos 2006/2007 Análise e Síntese de Algoritmos (CLR, Cap. 26) 24 12