You are on page 1of 9

Algoritmo de Dijkstra

El algoritmo de Dijkstra, tambin llamado algoritmo de caminos mnimos, es un algoritmo para la determinacin del camino ms corto dado un vrtice origen al resto de vrtices en un grafo dirigido y con pesos en cada arista. Su nombre se refiere a Edsger Dijkstra, quien lo describi por primera vez en 1959. La idea subyacente en este algoritmo consiste en ir explorando todos los caminos ms cortos que parten del vrtice origen y que llevan a todos los dems vrtices; cuando se obtiene el camino ms corto desde el vrtice origen, al resto de vrtices que componen el grafo, el algoritmo se detiene. El algoritmo es una especializacin Ejecucin del algoritmo de Dijkstra. de la bsqueda de costo uniforme, y como tal, no funciona en grafos con aristas de costo negativo (al elegir siempre el nodo con distancia menor, pueden quedar excluidos de la bsqueda nodos que en prximas iteraciones bajaran el costo general del camino al pasar por una arista con costo negativo).

Contenido
1 Algoritmo 2 Complejidad 3 Pseudocdigo 4 Otra versin en pseudocdigo sin cola de prioridad 5 Implementacin 5.1 C++ 5.2 C++ un poco ms simple con arreglos 5.3 C++ mediante Heaps 6 Enlaces externos

Algoritmo
Teniendo un grafo dirigido ponderado de N nodos no aislados, sea x el nodo inicial, un vector D de tamao N guardar al final del algoritmo las distancias desde x al resto de los nodos. 1. Inicializar todas las distancias en D con un valor infinito relativo ya que son desconocidas al principio, exceptuando la de x que se debe colocar en 0 debido a que la distancia de x a x sera 0. 2. Sea a = x (tomamos a como nodo actual). 3. Recorremos todos los nodos adyacentes de a, excepto los nodos marcados, llamaremos a estos vi. 4. Si la distancia desde x hasta vi guardada en D es mayor que la distancia desde x hasta a sumada a la

1 of 9

11/02/2012 17:17

distancia desde a hasta vi; esta se sustituye con la segunda nombrada, esto es: si (Di > Da + d(a, vi)) entonces D i = Da + d(a, vi) 5. M arcamos como completo el nodo a. 6. Tomamos como prximo nodo actual el de menor valor en D (puede hacerse almacenando los valores en una cola de prioridad) y volvemos al paso 3 mientras existan nodos no marcados. Una vez terminado al algoritmo, D estar completamente lleno.

Complejidad
Orden de complejidad del algoritmo: O(|V|2+|E|) = O(|V|2) sin utilizar cola de prioridad, O((|E|+|V|) log |V|) utilizando cola de prioridad (por ejemplo un montculo). Podemos estimar la complejidad computacional del algoritmo de Dijkstra (en trminos de sumas y comparaciones). El algoritmo realiza a lo ms n-1 iteraciones, ya que en cada iteracin se aade un vrtice al conjunto distinguido. Para estimar el nmero total de operaciones basta estimar el nmero de operaciones que se llevan a cabo en cada iteracin. Podemos identificar el vrtice con la menor etiqueta entre los que no estn en Sk realizando n-1 comparaciones o menos. Despus hacemos una suma y una comparacin para actualizar la etiqueta de cada uno de los vrtices que no estn en Sk. Por tanto, en cada iteracin se realizan a lo sumo 2(n-1) operaciones, ya que no puede haber ms de n-1 etiquetas por actualizar en cada iteracin. Como no se realizan ms de n-1 iteraciones, cada una de las cuales supone a lo ms 2(n-1) operaciones, llegamos al siguiente teorema. TEOREMA: El Algoritmo de Dijkstra realiza O(n2) operaciones (sumas y comparaciones) para determinar la longitud del camino ms corto entre dos vrtices de un grafo ponderado simple, conexo y no dirigido con n vrtices.

Pseudocdigo
Estructura de datos auxiliar: Q = Estructura de datos Cola de prioridad (se puede implementar con un montculo)
DIJKSTRA (Grafo G, nodo_fuente s) para u V[G] hacer distancia[u] = INFINITO padre[u] = NULL distancia[s] = 0 Encolar (cola, grafo) mientras que cola no es vaca hacer u = extraer_minimo(cola) para v adyacencia[u] hacer si distancia[v] > distancia[u] + peso (u, v) hacer distancia[v] = distancia[u] + peso (u, v) padre[v] = u

Otra versin en pseudocdigo sin cola de prioridad

2 of 9

11/02/2012 17:17

funcin Dijkstra (Grafo G, nodo_salida s) //Usaremos un vector para guardar las distancias del nodo salida al resto entero distancia[n] //Inicializamos el vector con distancias iniciales booleano visto[n] //vector de boleanos para controlar los vertices de los que ya tenemos la distancia mnima para cada w V[G] hacer Si (no existe arista entre s y w) entonces distancia[w] = Infinito //puedes marcar la casilla con un -1 por ejemplo Si_no distancia[w] = peso (s, w) fin si fin para distancia[s] = 0 visto[s] = cierto //n es el nmero de vertices que tiene el Grafo mientras que (no_esten_vistos_todos) hacer vertice = coger_el_minimo_del_vector distancia y que no este visto; visto[vertice] = cierto; para cada w sucesores (G, vertice) hacer si distancia[w]>distancia[vertice]+peso (vertice, w) entonces distancia[w] = distancia[vertice]+peso (vertice, w) fin si fin para fin mientras fin funcin

Al final tenemos en el vector distancia en cada posicin la distancia mnima del vertice salida a otro vertice cualquiera.

Implementacin
C++

3 of 9

11/02/2012 17:17

#include <cmath> #include <cstring> #include <iostream> using namespace std; int destino, origen, vertices = 0; int *costos = NULL; void dijkstra(int vertices, int origen, int destino, int *costos) { int i, v, cont = 0; int *ant, *tmp; int *z; /* vertices para los cuales se conoce el camino minimo */ double min; double *dist = new double[vertices]; /* vector con los costos de dos caminos */ /* aloca las lineas de la matriz */ ant = new int[vertices]; tmp = new int[vertices]; z = new int[vertices]; for (i = 0; i < vertices; i++) { if (costos[(origen - 1) * vertices + i] !=- 1) { ant[i] = origen - 1; dist[i] = costos[(origen-1)*vertices+i]; } else { ant[i]= -1; dist[i] = HUGE_VAL; } z[i]=0; } z[origen-1] = 1; dist[origen-1] = 0; /* Bucle principal */ do { /* Encontrando el vertice que debe entrar en z */ min = HUGE_VAL; for (i=0;i<vertices;i++) if (!z[i]) if (dist[i]>=0 && dist[i]<min) { min=dist[i];v=i; } /* Calculando las distancias de los nodos vecinos de z */ if (min != HUGE_VAL && v != destino - 1) { z[v] = 1; for (i = 0; i < vertices; i++) if (!z[i]) { if (costos[v*vertices+i] != -1 && dist[v] + costos[v*vertices+i] < dist[i] = dist[v] + costos[v*vertices+i]; ant[i] =v; } } } } while (v != destino - 1 && min != HUGE_VAL); /* Muestra el resultado de la bsqueda */ cout << "\tDe " << origen << " para "<<destino<<" \t"; if (min == HUGE_VAL) { cout <<"No Existe\n";

4 of 9

11/02/2012 17:17

C++ un poco ms simple con arreglos


Otra posible implementacin del algoritmo de Dijkstra incluye un arreglo para las distancias. Esto hace la implementacin ms simple, pero no es eficiente en uso de memoria y adems la versin presentada est limitada en el nmero de nodos del grafo.

5 of 9

11/02/2012 17:17

#include <iostream> #include <limits.h> #include <float.h> #define MAXNODOS 500 #define INDEFINIDO -1 // tamao mximo de la red

int N; float dist[MAXNODOS][MAXNODOS]; float minimo[MAXNODOS]; int anterior[MAXNODOS]; bool visitado[MAXNODOS]; bool minimoNodoNoVisitado (int * nodo) { int candidato = -1; for (int n = 0; n < N; n++) { if (!visitado[n] && (minimo[n] < minimo[candidato] || candidato == -1) candidato = n; } } *nodo = candidato; return candidato != -1; } void dijkstra (int origen, int destino) { minimo[origen] = 0.0; int nodo;

while (minimoNodoNoVisitado(&nodo)) { if (minimo[nodo] == FLT_MAX) return; // otros vrtices son inaccesib visitado[nodo] = true; for (int n = 0; n < N; n++) { if (!visitado[n] && distancia[nodo][n] < 1.0) { float posibleMin = minimo[nodo] + distancia[nodo][n]; if (posibleMin < minimo[n]) { minimo[n] = posibleMin; anterior[n] = nodo; } } } } } void camino_minimo (int inicio, int final) { if (inicio != final) { camino_minimo (inicio, anterior[final]); cout << ", "; } cout << final; } int main(int argc, char **argv) { int M, inicio, final; // inicializar matriz de distancias y camino minimo cin >> N; for (int k = 0; k < N; k++) { anterior[k] = INDEFINIDO; visitado[k] = false;

6 of 9

11/02/2012 17:17

C++ mediante Heaps


Otra posible implementacin del algoritmo de Dijkstra es mediante montculos binarios.

7 of 9

11/02/2012 17:17

struct T_Heap{ A monticulo; int num_elem; }; void CrearHeap(T_Heap& heap){ heap.num_elem= 0; for (int i=0;i<MAX_HEAP;i++){ heap.monticulo[i]= NULL; }//for } void Intercambiar(T_Heap& heap, int i, int j){ T_Lista aux; aux= heap.monticulo[i]; heap.monticulo[i]= heap.monticulo[j]; heap.monticulo[j]= aux; } void Meter(T_Heap& heap, const T_Lista& elem){ int k; k= heap.num_elem; heap.monticulo[k]= elem; while(k != 0 || (heap.monticulo[k]->peso > heap.monticulo[((k-1)/ 2)]->peso){ Intercambiar(heap,k,((k-1)/2)); k= (k-1)/2; }//while heap.num_elem++; } void Sacar(T_Heap& heap, int& elem){ int k; elem= heap.monticulo[0]; heap.monticulo[0]= heap.monticulo[heap.num_elem-1]; heap.monticulo[heap.num_elem-1]= NULL; heap.num_elem--; k= 0; while(k<heap.num_elem && (heap.monticulo[k]->peso < heap.monticulo[2*k+1]->peso || heap.monticulo[k]->peso < heap.monticulo[2*k+2]->peso)){ if (heap.monticulo[k] < heap.monticulo[2*k+1]){ Intercambiar(heap,k,2*k+1); k= 2*k+1; }else{ Intercambiar(heap,k,2*k+2); k= 2*k+2; }//if }//while } bool HeapLleno(const T_Heap& heap){ return(heap.num_elem== MAX_HEAP); } bool HeapVacio(const T_Heap& heap){ return(heap.num_elem== 0); } void DestruirHeap(T_Heap& heap){ for (int i=0;i<MAX_HEAP;i++){ heap.monticulo[i]= NULL; }//for heap.num_elem= 0; }

8 of 9

11/02/2012 17:17

Esta es una implementacin del algoritmo de Dijkstra mediante montculos binarios, que es capaz de dar los mejores resultados para que el algoritmo de Johnson sea ms eficiente. La implementacin del algoritmo devuelve un array de elementos precedentes y otro de distancias, mediante el primero se puede seguir el camino de menor coste desde el nodo pasado como argumento a cualquier otro nodo del grafo, y si paralelamente vamos sumando las distancias del otro array, obtenemos el coste total de dichos caminos mnimos.
void Dijkstra(const T_Grafo& grafo, int origen, T_Vector& distancias, T_Vector& previos { T_Vector marcados; T_Heap colap; T_Lista aux; InicializarVector(distancias); // inicializa los elementos a -1 InicializarVector(previos); InicializarVector(marcados); distancias[origen]= 0; marcados[origen]= 0; CrearHeap(colap); MeterAdyacentes(colap, grafo, origen, marcados); while (!HeapVacio(colap){ aux = Sacar(colap); marcados[aux->origen]= 0; MeterAdyacentes(colap, grafo, aux->origen, marcados); while (aux != NULL){ if (distancias[aux->destino] > (distancias[aux->origen] + aux->peso)){ distancias[aux->destino]= distancias[aux->origen] + aux->peso; padre[aux->destino] = aux->origen; }//if aux= aux->sig; }//while }//while }

Enlaces externos
Presentacin del Algoritmo de Dijkstra Applets en Java para probar el algoritmo de Dijkstra (Ingls) Graph mdulo Perl en CPAN Bio::Coordinate::Graph mdulo Perl en CPAN que implementa el algoritmo de Dijkstra Video Tutorial en VideoPractico.com de Dijkstra giswiki.net Algoritmo de Dijkstra en lenguajes como PHP, Actionscript y otros Categoras: Algoritmos de bsqueda | Algoritmos de grafos

9 of 9

11/02/2012 17:17