Floyd-Warshall: caminhos mínimos entre todos os pares
Preencha a matriz de distâncias entre todos os pares usando o algoritmo de Floyd-Warshall com três laços aninhados e aplique-o para encontrar o menor número de saltos entre todos os pares de nós.
Floyd-Warshall: caminhos mínimos entre todos os pares é uma aula grátis de Coding Interview Prep no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Coding Interview Prep, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Coding Interview Prep inclui 4 aulas no total.
Caminhos mais curtos entre todos os pares
Floyd-Warshall calcula os caminhos mais curtos entre cada par de nós em um grafo ponderado — inclusive em grafos com pesos negativos nas arestas (mas não com ciclos negativos). Executar Dijkstra a partir de cada origem leva O(V × (V+E) log V); Floyd-Warshall é executado em O(V³), independentemente da densidade das arestas. Para grafos densos com V ≤ 500, Floyd-Warshall costuma ser mais simples e ter velocidade comparável.
A ideia principal: nós intermediários
A ideia central de Floyd-Warshall: dp[i][j][k] = caminho mais curto de i até j usando apenas os nós {0, 1, ..., k} como intermediários. Ou o caminho mais curto usa o nó k como intermediário, ou não usa. Se usar: dp[i][j][k] = dp[i][k][k-1] + dp[k][j][k-1]. Se não usar: dp[i][j][k] = dp[i][j][k-1]. Como a terceira dimensão avança apenas para frente, ela pode ser eliminada — atualizamos no próprio local.
Inicialização da matriz de distâncias
Comece com uma matriz V×V: dist[i][i] = 0 (distância até si próprio igual a zero), dist[i][j] = weight para arestas diretas e dist[i][j] = inf para pares sem aresta. Em seguida, percorra todos os nós intermediários k, atualizando os pares (i, j). O laço externo sobre k deve vir primeiro para que os caminhos através de um conjunto crescente de intermediários permitidos sejam construídos corretamente.
def floyd_warshall(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V):
dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w # directed graph
for k in range(V): # intermediate node
for i in range(V):
for j in range(V):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return distImplementação completa com exemplo
Vamos acompanhar o Floyd-Warshall em um grafo com 4 nós. Depois de processar cada nó intermediário k, a matriz é preenchida com caminhos mais curtos que passam por k. O algoritmo trata naturalmente vários saltos ao construir os caminhos mais curtos de forma incremental.
def floyd_warshall(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V):
dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w
for k in range(V):
for i in range(V):
for j in range(V):
if dist[i][k] != INF and dist[k][j] != INF:
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
return dist
V = 4
edges = [(0,1,3),(0,2,7),(1,2,1),(1,3,5),(2,3,2)]
dist = floyd_warshall(V, edges)
for row in dist:
print([x if x != float('inf') else 'INF' for x in row])Detecção de ciclos negativos
Depois de executar Floyd-Warshall, verifique a diagonal principal: se algum dist[i][i] < 0, existe um ciclo negativo que passa pelo nó i. Isso ocorre porque um ciclo negativo permite chegar a i partindo de i com custo negativo. Se não existir nenhum ciclo negativo, todas as entradas da diagonal permanecerão iguais a 0.
def has_negative_cycle_fw(V, edges):
dist = floyd_warshall(V, edges)
for i in range(V):
if dist[i][i] < 0:
return True # negative cycle through node i
return False
# Negative cycle: 0->1->2->0 with weights 1,-3,1 (sum=-1)
edges_neg = [(0,1,1),(1,2,-3),(2,0,1)]
print(has_negative_cycle_fw(3, edges_neg)) # TrueReconstrução do caminho
Para reconstruir o caminho real de i até j, mantenha uma matriz next[i][j]: inicialmente, next[i][j] = j para arestas diretas. Ao atualizar através do intermediário k, defina next[i][j] = next[i][k]. Para recuperar o caminho: comece em i e siga os ponteiros de next até chegar a j. Isso acrescenta espaço O(V²) e O(V) por reconstrução de caminho.
def fw_with_path(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
nxt = [[None]*V for _ in range(V)]
for i in range(V): dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w; nxt[u][v] = v
for k in range(V):
for i in range(V):
for j in range(V):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
nxt[i][j] = nxt[i][k]
return dist, nxt
def get_path(nxt, i, j):
if nxt[i][j] is None: return []
path = [i]
while i != j:
i = nxt[i][j]; path.append(i)
return pathFecho transitivo
Uma variante mais simples: o fecho transitivo responde à pergunta “o nó j é alcançável a partir do nó i?” para todos os pares. Substitua as distâncias por valores booleanos: reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j]). Isso é Floyd-Warshall usando OR booleano em vez de adição e mínimo. Inicialize reach[i][i] = True e reach[i][j] = True para arestas diretas.
def transitive_closure(V, edges):
reach = [[False]*V for _ in range(V)]
for i in range(V):
reach[i][i] = True
for u, v, _ in edges:
reach[u][v] = True
for k in range(V):
for i in range(V):
for j in range(V):
reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j])
return reach
edges = [(0,1,1),(1,2,1)]
R = transitive_closure(3, edges)
print(R[0][2]) # True (0 can reach 2 via 0->1->2)Complexidade e quando usar
Floyd-Warshall: O(V³) de tempo, O(V²) de espaço. Para grafos densos (E ≈ V²) com V ≤ 300, ele é mais rápido que executar Dijkstra V vezes (também O(V³ nesse caso). Para grafos esparsos com V = 1000 e E = 3000, V execuções de Dijkstra custam O(V×E×log V) ≈ 33M, enquanto Floyd-Warshall custa O(V³) = 10⁹ — Dijkstra vence. Saiba quando cada um é apropriado.
Número mínimo de saltos entre todos os pares
Defina todos os pesos das arestas como 1 (ou use uma matriz de adjacência booleana com Floyd-Warshall, usando soma em vez de mínimo): dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]). Isso calcula o número mínimo de saltos entre todos os pares — um resultado de BFS entre todos os pares, mas calculado com uma única passagem de Floyd-Warshall de O(V³).
def min_hops_all_pairs(V, adj_list):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V):
dist[i][i] = 0
for j in adj_list[i]:
dist[i][j] = 1
for k in range(V):
for i in range(V):
for j in range(V):
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
return dist
adj = [[1,2],[2],[3],[],[]]
print(min_hops_all_pairs(5, adj)[0]) # [0, 1, 1, 2, INF]Contexto de entrevista: quando os entrevistadores perguntam sobre Floyd-Warshall
Floyd-Warshall aparece em entrevistas em questões que envolvem: (1) distâncias entre todos os pares em um grafo pequeno, (2) verificar se existe algum ciclo com peso total negativo, (3) calcular caminhos mais curtos em problemas de propagação de restrições e (4) problemas que pedem explicitamente soluções O(V³), em que V ≤ 200. Mencione sempre a estrutura de três laços e o requisito de não haver ciclos negativos para garantir a correção.
Grafos não direcionados com Floyd-Warshall
Para grafos não direcionados, adicione as duas direções para cada aresta: dist[u][v] = dist[v][u] = weight. O restante do algoritmo é idêntico. A matriz resultante é simétrica: dist[i][j] == dist[j][i] para todos os pares. Ao inicializar, tome cuidado para não atribuir acidentalmente arestas direcionais — as arestas não direcionadas devem ser adicionadas nas duas direções à matriz inicial antes da execução dos três laços.
def fw_undirected(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V): dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w
dist[v][u] = w # both directions for undirected
for k in range(V):
for i in range(V):
for j in range(V):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return distVerificação rápida
Teste sua compreensão dos conceitos de Estruturas de Dados e Algoritmos — Preparação para Entrevistas de Programação desta lição.
Recapitulação da lição
Nesta lição, você aprendeu que: Floyd-Warshall calcula os caminhos mais curtos entre todos os pares com três laços aninhados e a recorrência dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]), os ciclos negativos podem ser detectados verificando se algum dist[i][i] < 0 após a conclusão e o algoritmo é executado em tempo O(V³) e espaço O(V²). Em seguida, retomaremos as aplicações de caminhos mais curtos com Network Delay Time e técnicas de reconstrução de caminhos.
Aprenda Coding Interview Prep com um tutor de IA — grátis
Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.
- Cursos
- 90
- Aulas
- 360
Perguntas Frequentes
A aula “Floyd-Warshall: caminhos mínimos entre todos os pares” é grátis?
Sim — o texto completo de “Floyd-Warshall: caminhos mínimos entre todos os pares” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Coding Interview Prep, atualize para CoddyKit PRO. O curso de Coding Interview Prep inclui 4 aulas no total.
O que vou aprender em “Floyd-Warshall: caminhos mínimos entre todos os pares”?
Preencha a matriz de distâncias entre todos os pares usando o algoritmo de Floyd-Warshall com três laços aninhados e aplique-o para encontrar o menor número de saltos entre todos os pares de nós. Você pratica Coding Interview Prep com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Coding Interview Prep?
Nenhuma experiência prévia é necessária. Coding Interview Prep no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Floyd-Warshall: caminhos mínimos entre todos os pares”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Coding Interview Prep?
Sim. Cada aula de Coding Interview Prep inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Algoritmo de Dijkstra com fila de prioridades
- Bellman-Ford e ciclos negativos
- Floyd-Warshall: caminhos mínimos entre todos os pares
- Tempo de atraso da rede e reconstrução de caminhos