Professional Documents
Culture Documents
El algoritmo de Johnson es una forma de encontrar el camino ms corto entre todos los
pares de vrtices de un grafo dirigido disperso. Permite que las aristas tengan pesos
negativos, si bien no permite ciclos de peso negativo. Funciona utilizando el algoritmo de
Bellman-Ford para hacer una transformacin en el grafo inicial que elimina todas las aristas de
peso negativo, permitiendo por tanto usar el algoritmo de Dijkstra en el grafo transformado. Su
nombre viene de Donald B. Johnson, quien fuera el primero en publicar la tcnica en 1977.
Anlisis de la complejidad[editar]
La complejidad temporal de este algoritmo, usando montculos de Fibonacci en la
implementacin del algoritmo de Dijkstra, es de O(V2log V + VE): el algoritmo usa un tiempo
de O(VE) para la fase Bellman-Ford del algoritmo, y O(V log V + E) para cada una de
las V instancias realizadas del algoritmo de Dijkstra. Entonces, cuando el grafo es disperso el
tiempo total del algoritmo puede ser menor que el algoritmo de Floyd-Warshall, que resuelve el
mismo problema en un tiempo de O(V3).
Ejemplo[editar]
Las etapas del algoritmo de Johnson estn descritas en la siguiente
ilustracin:
Implementacin[editar]
La estructura de datos para almacenar el grafo consiste en una representacin de cada vrtice
como una lista de las aristas que parten del mismo. Estas aristas constan de un origen, un
destino y un peso. El conjunto de vrtices se representa como un array de vrtices y un ndice
que nos indica el ltimo vrtice empleado del array.
La implementacin del algoritmo devuelve una matriz de elementos precedentes y otra de
distancias, mediante la primera se puede seguir el camino de menor coste desde un nodo
dado a cualquier otro nodo del grafo, y si paralelamente vamos sumando las distancias de la
otra matriz, obtenemos los costes totales de dichos caminos mnimos.
Pseudocdigo[editar]
Tipos
Arista = REGISTRO
o : NATURAL
d : NATURAL
peso : INT
sig : NATURAL
FIN
LAristas = PUNTERO A Arista
TGrafo = ARRAY [1..N] DE LAristas
THv = ARRAY [1..N] DE ENTERO
TVector = ARRAY [1..N] DE ENTERO
TMatriz = ARRAY [1..N] DE TVector
//suponemos ig>1
PROC Johnson (grafo: TGrafo; ig: NATURAL; distancias: TMatriz ;
previos: TMatriz)
VARIABLES
i : NATURAL
p : LAristas
min_caminos : THv
aux_dist, aux_prev : TVector
INICIO
grafo[ig] nueva_arista(ig,1,0,NULO)
inc(ig)
p grafo[ig]
PARA i 2 HASTA ig-2 HACER
p^.sig nueva_arista(ig,i,0,NULO)
p p^.sig
FIN
BellmanFord(grafo,ig, min_caminos)
PARA i 1 HASTA ig-1 HACER
p grafo[i]
MIENTRAS (p != NULO) HACER
p^.peso p^.peso + min_caminos[p^.o] - min_caminos[p^.d]
p p^.sig
FIN
FIN
PARA i 1 HASTA ig-2 HACER
Dijkstra(grafo,i, aux_dist,aux_prev)
// devuelve los
C++[editar]
#include <cstdlib>
using namespace std;
struct Arista{
unsigned o;
unsigned d;
int peso;
LAristas sig;
};
typedef LAristas Arista*;
typedef TGrafo LArista[N];
typedef TVector int[N];
typedef TMatriz TVector[N];
//suponemos ig>1
void johnson(const TGrafo &grafo, int ig, TMatriz &distancias, TMatriz
&previos){
Arista* p;
TVector min_caminos;
TVector aux_dist;
TVector aux_prev;
grafo[ig] = nueva_arista(ig,1,0,NULL);
ig++;
p = grafo[ig];
for(unsigned i=2; i<=ig-2; i++){
p->sig = nueva_arista(ig,i,0,NULL);
p = p->sig;
}
BellmanFord(grafo,ig, min_caminos);
for(unsigned i=1; i<=ig-1; i++){
p = grafo[i];
while(p != NULL){
p->peso = p->peso + min_caminos[p->o] - min_caminos[p->d];
p = p->sig;
}
}
for(unsigned i=1; i<=ig-2; i++){
Dijkstra(grafo,i-1, aux_dist,aux_prev) // devuelve los
caminos mnimos desde el ltimo nodo
// a todos los dems.
previos[i-1] = aux_prev;
CalcularDistancias(grafo, previos, aux_dist,distancias); //
este algoritmo realiza la transformacin inversa a la
//
que habamos hecho antes sobre los pesos, para obtener
//
las distancias reales
}
}