Escolar Documentos
Profissional Documentos
Cultura Documentos
Grafos Parte2 Dijkstra PDF
Grafos Parte2 Dijkstra PDF
Algoritmo de Dijkstra
Descrio do algoritmo
O algoritmo de Dijkstra identifica, a partir de um vrtice do grafo, qual o custo mnimo entre
esse vrtice e todos os outros do grafo. No incio, o conjunto S contm somente esse vrtice,
chamado origem. A cada passo, selecionamos no conjunto de vrtices sobrando, o que o
mais perto da origem. Depois atualizamos, para cada vrtice sobrando, a sua distncia em
relao origem. Se passando pelo novo vrtice acrescentado, a distncia fica menor, essa
nova distncia que ser memorizada.
Suponhamos que o grafo representado por uma matriz de adjacncia onde temos o valor
se no existe aresta entre dois vrtices. Suponhamos tambm que os vrtices do grafo so
enumerados de 1 at n, isto , o conjunto de vrtices N = {1, 2, ..., n}. Utilizaremos tambm
um vetor D[2..n] que conter a distncia que separa todo vrtice do vrtice 1 (o vrtice do grafo
que o vrtice 1 escolhido arbitrariamente). Eis o algoritmo:
Figura 1
Passo v C D
Incio - {2,3,4,5} [50,30,100,10]
1 5 {2,3,4} [50,30,20,10]
2 4 {2,3} [40,30,20,10]
3 3 {2} [35,30,20,10]
Da maneira que o algoritmo foi apresentado, obtemos o custo do caminho mnimo para
qualquer vrtices, mas no obtemos o caminho mnimo. Para identificar esse caminho mnimo,
s acrescentar mais um vetor P[2..n], onde P[v] indica o vrtice que precede v no caminho
mais curto. A modificao do algoritmo para obter esse vetor simples. Primeiro devemos
inicializar esse vetor. Segundo, no mesmo momento que o vetor D atualizado, atualizamos
tambm o vetor P. O algoritmo modificado o seguinte:
Passo v C D P
Incio - {2,3,4,5} [50,30,100,10] [1,1,1,1]
1 5 {2,3,4} [50,30,20,10] [1,1,5,1]
2 4 {2,3} [40,30,20,10] [4,1,5,1]
3 3 {2} [35,30,20,10] [3,1,5,1]
Vemos que o estado final do vetor P [3,1,5,1]. Para saber qual o caminho mais curto entre
os vrtices 1 e 2, procuramos o valor na posio 2 desse vetor (no esquea que P e D so
indexados a partir de 2). O vetor indica que o ltimo vrtice antes do vrtice 2 o vrtice 3.
Repetimos de novo o mesmo processo para ver o caminho mais curto entre 1 e 3. No vetor, na
posio 3, temos o valor 1, que a origem. Ento, o caminho mais curto 1,3,2.
Para efetuar a prova, vamos primeiro definir o conceito de caminho especial mais curto. Seja
v1 a origem. Para qualquer vrtice vi que no faz parte do conjunto S, o caminho especial mais
curto o caminho mais curto para alcanar vi a partir de v1 e que passa somente por vrtices
do conjunto S.
Figura 2
Nesse caso, supondo que o grafo no contm nenhum peso negativo, a distncia at v
passando por x maior ou igual distncia at x. Como esse caminho comea com
um caminho especial at x e que por induo o comprimento D[x] dessa parte do
caminho mnimo, sabemos que a distncia total at v passando por x maior ou igual
a D[x]. Como v foi selecionado antes de x, devemos ter tambm D[x] D[v]. Isso
implica que o caminho em vermelho, que supostamente mais curto, deve possuir um
comprimento maior ou igual ao comprimento do caminho especial indicado em preto, o
que contradiz a hiptese. Portanto o caminho especial at v o mais curto.
2. Consideramos agora o que acontece com os outros vrtices diferentes de v que ficam
fora do conjunto S. Seja w tal vrtice. Quando v acrescentado no conjunto S tem
duas possibilidades no que concerne o caminho especial mais curto at w: ou ele fica
igual, ou ele passa agora por v. Vamos ento considerar o segundo caso.
Figura 3
Esse caminho no pode ser mais curto, pois j existe um caminho mais curto (ou igual)
at x que no inclui v (isso porque x j estava em S antes da adio de v e por induo
j tnhamos um caminho mais curto). Ento, o caminho especial mais curto o menor
entre o que passa por v antes de chegar a w e o que tnhamos antes de acrescentar v.
E isso exatamente o que o algoritmo verifica.
Anlise do algoritmo
A inicializao do algoritmo exige um tempo em O(n). O loop executado n-2 vezes e a cada
iterao todos os vrtices no atualmente no conjunto S so visitados. Na primeira iterao,
visitaremos n-1 vrtices, na segunda, n-2 vrtices, e assim por diante. Podemos ento deduzir
2
que o tempo de execuo em O(n ).
Nesse caso, o loop mais interno no vai visitar todos os vrtices do grafo, somente os que so
adjacentes ao ltimo vrtice acrescentado. No total, o teste interno ser executado a vezes, o
que proporcional a n no caso de um grafo esparso. Mas mesmo se isso melhora na prtica, o
2
algoritmo ainda em O(n ) porque devemos ainda visitar todos os elementos do conjunto C
para retirar o vrtice que possui o menor valor.
possvel melhorar mais ainda, usando, alm da estrutura de adjacncia, um heap que
contm um nodo para cada vrtice v do conjunto C, ordenados em ordem crescente pelo valor
D[v]. O tempo para inicializar o heap e em O(n). Consideramos agora o loop principal. Para
retirar o vrtice v do conjunto C que minimiza D[v], simplesmente retiramos o vrtice que est
na raiz do heap e ajustamos o heap. Sabemos que isso exige um tempo em O(log n). No que
concerne o loop mais interno, devemos considerar todo vrtice x adjacente a v que no
conjunto C. Nesse caso, talvez deveremos ajustar o valor D[x]. O ajustamento necessrio no
heap exige um tempo em O(log n). Em resumo, preciso retirar n-2 vezes um vrtice do
conjunto C (exigindo uma atualizao do heap a cada vez) e revisar o valor D[v] no mximo a
vezes (isso tambm exige uma atualizao do heap). Portanto, com essa implementao, o
tempo de execuo ser em O((a+n)log n). Se o grafo conexo, temos a n-1, e ento um
tempo de execuo em O(a log n).
Programao dinmica
O algoritmo de Dijkstra permite identificar todos os caminhos mais curtos a partir de um nico
vrtice de origem. Utilizando a programao dinmica, podemos obter o caminho mais curto
entre qualquer par de vrtices. Lembramos que a programao dinmica consiste
essencialmente em produzir solues intermedirias que sero utilizadas incrementalmente
para obter a soluo final. Vamos primeiro ver uma soluo interessante em teoria mas
ineficiente na prtica.
A idia do nosso primeiro algoritmo o seguinte. Seja um grafo direcionado representado por
uma matriz de adjacncia L[1..n,1..n]. Calculamos a cada etapa do algoritmo uma matriz D
onde cada elemento D[i,j] representa o valor do caminho mais curto de k arestas entre i e j. Na
etapa seguinte os valores das matrizes D e L so utilizadas para calcular a nova matriz D que
contm os valores para k+1 arestas. Para obter o novo valor D[i,j], consideramos o valor D[i,u]
+ L[u,j] para todo vrtice u e escolhemos o menor valor. Isto , consideramos todos o caminhos
de k vrtices a partir de i, acrescentamos, para cada um desses caminhos, a arestas que falta
para alcanar j e selecionamos o mais curto.
Eis o algoritmo:
Figura 4
4
Considerando agora o tempo de execuo desse algoritmo, vemos que ele est em O(n ). Ser
que d para fazer melhor? Sim, possvel. Vamos ver agora o algoritmo de Floyd, que tambm
retorna o caminho mais curto entre qualquer par de vrtices.
Para se convencer que o algoritmo funciona corretamente, de novo faremos um prova por
induo. No incio D[i,j] contm o valor da aresta entre i e j se tal aresta existe, seno. Como
inicialmente o conjunto C vazio, no pode ter vrtice intermedirio entre i e j, temos em D[i,j]
o valor do caminho mais curto. Suponhamos agora que a hiptese verdadeira para a iterao
k. Se caminho entre i e j que passa por k+1 mais curto, necessariamente os pedaos de i at
k e de k at j so tambm os mais curtos. J temos na matriz, nas posies D[i,k] e D[k,j], o
valor desses caminhos mais curtos. Como o programa compara a soma desses dois valores
com o valor encontrado em D[i,j] e escolhe o menor, tambm na etapa k+1 teremos os
caminhos mais curtos que passam pelos vrtices {1,2,...,k+1}.
3
muito fcil ver que o algoritmo tem um tempo de execuo em O(n ). Note que o mesmo
problema pode ser resolvido aplicando n vezes o algoritmo de Dijkstra, comeando cada vez
3
com um vrtice diferente. Nesse caso, teramos tambm um tempo de execuo em O(n ). Mas
isso no significa que ambos tm a mesma eficincia. O algoritmo de Floyd tem que inicializar
uma matriz de tamanho n x n. O algoritmo de Dijktra tem, dentro do primeiro loop, dois loops
onde cada uma exige um tempo de execuo na ordem de n. Tambm ele deve efetuar uma
2
inicializao que exige um tempo em O(n) (isso repetido n vezes vai dar um total em O(n )).
Lembramos que usando uma estrutura de heap, podemos obter uma implementao do
algoritmo de Dijkstra que est em O((a+n) log n), onde a o nmero de arestas. Aplicando n
2
vezes o algoritmo, obtemos um tempo de execuo de n x O((a+n) log n) = O((an + n ) log n).
Se o grafo esparso, pode ser melhor utilizar o algoritmo de Dijkstra. Se o nmero de arestas
se aproxima do grafo completo, provavelmente o algoritmo de Floyd ser melhor.
A descrio do algoritmo dada acima no permite identificar o caminho mais curto. Para obter
isso, podemos modificar o algoritmo de maneira semelhante ao que foi feito com o algoritmo de
Dijkstra. Utilizaremos uma matriz P onde cada elemento P[i,j] aponta no ltimo vrtice (diferente
de i) encontrado no caminho antes de chegar a j. A matriz P ser atualizada cada vez que uma
posio D[i,j] ser atualizada, colocando o ltimo vrtice k considerado. No incio, toda posio
da matriz P recebe o valor 0. No final, para identificar o caminho mais curto entre i e j, so
percorrer os ponteiros a partir de P[i,j] at chegar a uma entrada que tem valor 0. Eis a verso
modificada do algoritmo:
Com a matriz P retornada pelo algoritmo, vemos que o caminho mais curto de 1 at 3 passa
pelo vrtice 4. Isso porque o valor 4 aparece na posio (1,3) da matriz. Agora, para saber o
caminho inteiro, devemos procurar recursivamente o caminho mais curto de 1 at 4 e de 4 at
3. Procurando novamente na matriz P, vemos que na posio (4,3) h um 0, que indica que o
caminho de 4 at 3 direto. Na posio (1,4) da matriz aparece um 2, indicando que o caminho
mais curto de 1 at 4 passa pelo vrtice 2. Repetindo o processo, vemos que o caminhos mais
curtos de 1 at 2 e de 2 at 4 no contm outros vrtices intermedirios. Portanto, o caminho
mais curto entre 1 e 3 a sequncia dos vrtices 1,2,4,3.
Exerccios
Exerccio 1: Execute o algoritmo de Dijkstra com o grafo da figura 1, mas comeando com o
vrtice 4. A resposta a mesma?
Exerccio 2: Para cada grafo ilustrado na figura 5, mostre cada passo da execuo do
algoritmo de Dijkstra.
Figura 5
Exerccio 5: Para cada grafo ilustrado na figura 5, mostre cada passo da execuo do
algoritmo de Floyd.
Exerccio 6: Como o algoritmo de Floyd se comporta com um grafo que contm arestas de
peso negativo? (Considere os casos onde existem circuitos de valor negativo e os casos onde
no existe tal circuito)
Exerccio 7: Modifique o algoritmo de Floyd para determinar o nmero de caminhos entre cada
par de vrtices.