El algoritmo de Dijkstra, también llamado algoritmo de caminos mínimos, es un algoritmo para la determinación del camino más corto dado un vértice origen al resto de los vértices en un grafo 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 más cortos que parten del vértice origen y que llevan a todos los demás vértices; cuando se obtiene el camino más corto desde el vértice origen, al resto de vértices que componen el grafo, el algoritmo se detiene. El algoritmo es una especialización de la búsqueda de costo uniforme, y como tal, no funciona en grafos con aristas de coste negativo (al elegir siempre el nodo con distancia menor, pueden quedar excluidos de la búsqueda nodos que en próximas iteraciones bajarían el costo general del camino al pasar por una arista con costo negativo).
Una de sus aplicaciones más importantes reside en el campo de la telemática, gracias a el, podemos resolver grafos con muchos nodos, los cuales serian muy complicados de hacer sin dicho algoritmo, encontrando así las rutas más cortas entre un origen y todos los destinos en una red.
Algoritmo de Dijkstra | ||
---|---|---|
Ejecución del algoritmo de Dijkstra | ||
Tipo | Algoritmo de búsqueda | |
Problema que resuelve | Problema del camino más corto | |
Estructura de datos | Grafo | |
Creador | Edsger Dijkstra | |
Fecha | 1959 | |
Clase de complejidad | P | |
Tiempo de ejecución | ||
Peor caso |
Algoritmo
Teniendo un grafo dirigido ponderado de N nodos no aislados, sea x el nodo inicial, un vector D de tamaño N guardará al final del algoritmo las distancias desde x al resto de los nodos.
- 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 sería 0.
- Sea a = x (tomamos a como nodo actual).
- Recorremos todos los nodos adyacentes de a, excepto los nodos marcados, llamaremos a estos nodos no marcados vi.
- Para el nodo actual, calculamos la distancia tentativa desde dicho nodo a sus vecinos con la siguiente fórmula: dt(vi) = Da + d(a,vi). Es decir, la distancia tentativa del nodo ‘vi’ es la distancia que actualmente tiene el nodo en el vector D más la distancia desde dicho el nodo ‘a’ (el actual) al nodo vi. Si la distancia tentativa es menor que la distancia almacenada en el vector, actualizamos el vector con esta distancia tentativa. Es decir: Si dt(vi) < Dvi → Dvi = dt(vi)
- Marcamos como completo el nodo a.
- Tomamos como próximo 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+|A|) = O(|V|2) sin utilizar cola de prioridad, O((|A|+|V|) log |V|) = O(|A| log |V|) utilizando cola de prioridad (por ejemplo un montículo). Por otro lado, si se utiliza un Montículo de Fibonacci, sería O(|V| log |V|+|A|).
Podemos estimar la complejidad computacional del algoritmo de Dijkstra (en términos de sumas y comparaciones). El algoritmo realiza a lo más n-1 iteraciones, ya que en cada iteración se añade un vértice al conjunto distinguido. Para estimar el número total de operaciones basta estimar las que se llevan a cabo en cada iteración. Podemos identificar el vértice con la menor etiqueta entre los que no están en Skrealizando n-1 comparaciones o menos. Después hacemos una suma y una comparación para actualizar la etiqueta de cada uno de los vértices que no están en Sk. Por tanto, en cada iteración se realizan a lo sumo 2(n-1) operaciones, ya que no puede haber más de n-1 etiquetas por actualizar en cada iteración. Como no se realizan más de n-1 iteraciones, cada una de las cuales supone a lo más 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 más corto entre dos vértices de un grafo ponderado simple, conexo y no dirigido con n vértices.
Pseudocódigo
Estructura de datos auxiliar: Q = Estructura de datos Cola de prioridad (se puede implementar con un montículo)
DIJKSTRA (Grafo G, nodo_fuente s) para u ∈ V[G] hacer distancia[u] = INFINITO padre[u] = NULL visto[u] = false distancia[s] = 0 adicionar (cola, (s, distancia[s])) mientras que cola no es vacía hacer u = extraer_mínimo(cola) visto[u] = true para todos v ∈ adyacencia[u] hacer si no visto[v] y distancia[v] > distancia[u] + peso (u, v) hacer distancia[v] = distancia[u] + peso (u, v) padre[v] = u adicionar(cola,(v, distancia[v]))
Otra versión en pseudocódigo sin cola de prioridad
función 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 vértices de los que ya tenemos la distancia mínima 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 número de vértices que tiene el Grafo mientras que (no_estén_vistos_todos) hacer vértice = coger_el_mínimo_del_vector distancia y que no esté visto; visto[vértice] = cierto; para cada w ∈ sucesores (G, vértice) hacer si distancia[w]>distancia[vértice]+peso (vértice, w) entonces distancia[w] = distancia[vértice]+peso (vértice, w) fin si fin para fin mientras fin función.
Al final tenemos en el vector distancia en cada posición la distancia mínima del vértice salida a otro vértice cualquiera.
Otra versión en C del Algoritmo de Dijkstra
#define MAX_NODES 1024 /* número máximo de nodos */ #define INFINITY 1000000000 /* un número mayor que cualquier ruta máxima */ int n, dist[MAX_NODES][MAX_NODES]; /* dist[i][ j] es la distancia de i a j */ void shortest_path(int s, int t, int path[]) { struct state { /* la ruta en la que se está trabajando */ int predecessor; /* nodo previo */ int length; /* longitud del origen a este nodo */ enum {permanent, tentative} label; /* estado de la etiqueta */ } state[MAX_NODES]; int i, k, min; struct state *p; for (p = &state[0]; p < &state[n]; p++) { /* estado de inicialización*/ p->predecessor = -1; p->length = INFINITY; p->label = tentative; } state[t].length = 0; state[t].label = permanent; k = t; /* k es el nodo de trabajo inicial */ do{ /* ¿hay una ruta mejor desde k? */ for (i = 0; i < n; i++) /* este grafo tiene n nodos */ if (dist[k][i] != 0 && state[i].label == tentative) { if (state[k].length + dist[k][i] < state[i].length) { state[i].predecessor = k; state[i].length = state[k].length + dist[k][i]; } } /* Encuentra el nodo etiquetado tentativamente con la etiqueta menor. */ k = 0; min = INFINITY; for (i = 0; i < n; i++) if (state[i].label == tentative && state[i].length < min) { min = state[i].length; k = i; } state[k].label = permanent; } while (k != s); /* Copia la ruta en el arreglo de salida. */ i = 0; k = s; do {path[i++] = k; k = state[k].predecessor; } while (k >= 0);
La Fórmula del área de Gauss, Fórmula de la Lazada o Algoritmo de la Lazada, es un algoritmo matemático usado para calcular el área de un polígono simple cuyos vértices están descritos como pares de coordenadas en el plano.1 2Es conocido como fórmula de la lazada debido al constante cruce de productos de las correspondientes coordenadas de cada par de vértices, similar al atar una lazada.1 También recibe el nombre de Fórmula del área de Gauss en honor a Carl Friedrich Gauss. Tiene múltiples aplicaciones en agrimensura e ingeniería de montes entre otras áreas.
No hay comentarios:
Publicar un comentario