Um caminho C de um vértice r a um vértice s em um grafo é mínimo se não existe outro caminho de r a s que tenha menos arcos que C. (Exercício: Mostre que todo caminho mínimo é simples.)
A distância
de
um vértice r a
um vértice s
é o número de arcos de um caminho mínimo de r a s.
(Cuidado: não faz sentido dizer a menor distância
ou a distância mínima
:
distância já é mínima por definição.)
Portanto, dizer que a distância de r a
s é d
significa duas coisas:
(1) existe um caminho de r a
s com exatamente d arcos e
(2) não existe caminho de r a
s com menos que d arcos.
Note que a distância de r a s
pode ser diferente da distância de s
a r.
(Por isso evito dizer
distância entre r e s
.)
Problema das Distâncias: Dados vértices r e s, calcular a distância de r a s.
Se não existe caminho algum de r a s, ou seja, se s não está no território de r, podemos dizer que a distância é infinita.
Para resolver o problema das distâncias, basta modificar ligeiramente o algoritmo de busca em largura. Para cada vértice v, a distância de r a v será vdist. Se a distância de r a v ainda não está definida, diremos que vdist vale −1. (Faria mais sentido dizer que vdist vale ∞ nesse caso. Poderíamos (por que?) usar o número de vértices do grafo, n, para representar ∞.)
Cada iteração começa com uma fila de vértices ativos; no início da primeira iteração, r é o unico vértice da fila. Cada iteração consiste no seguinte:
se a fila está vazia
então pare
senão seja v o primeiro vértice da fila
senão para cada vértice w adjacente a v
senão se wdist ≡ −1
senão então wdist = vdist + 1
senão então insira w no final da fila
senão retire v da fila
A fila garante que dá tudo certo: a cada passagem pela linha 7, wdist é a distância correta de r a w. No fim do algoritmo, wdist ≡ −1 se e só se w está fora do território de r.
#define dist x.I
n = gn; v0 = gvertices;
for (v = v0; v < v0 + n; v++) vdist = −1;
rdist = 0;
for (d = 0; d < n; d++)
for (v = v0; v < v0 + n; v++)
if (vdist ≡ d)
for (a = varcs; a ≠ NULL; a = anext)
if (atipdist ≡ −1)
atipdist = d + 1;
Problema: Dados vértices r e s, encontrar um caminho mínimo de r a s. Como já vimos, o número de arcos de um tal caminho é a distância de r a s.
Para encontrar um caminho mínimo,
faça uma adaptação do algoritmo das distâncias visto acima.
O algoritmo calculará uma
arborescência
que cobrirá o território de r.
Se a arborescência atingir s,
basta voltar
ao longo dos arcos da arborescência
(de s para o seu
predecessor e assim em diante)
até chegar ao vértice r.
Esse percurso é o inverso do caminho desejado.
Suponha que cada arco do grafo tem um comprimento (= length), que é um número inteiro não-negativo. (Na estrutura de dados do SGB, o comprimento de um arco a é alen.) Re-defina o conceito de distância de maneira apropriada: o comprimento de um caminho deverá ser a soma dos comprimentos de seus arcos. Podemos agora perguntar pela distância de um vértice r a um vértice s. Podemos também perguntar por um caminho mínimo (nesse novo sentido) de r a s.
O módulo GB_DIJK do SGB resolve esses problemas e implementa o célebre algoritmo de Dijkstra. O módulo é um tanto complexo porque é muito genérico, permitindo, entre outras coisas, que alguns arcos tenham comprimento negativo.