Sei sulla pagina 1di 12

Carrera:

Ingeniería de Sistemas
Asignatura
Matemática Discreta
Tema:

Estudiantes:
Robinson Ttamiña Pacheco
Emilio García Gutiérrez
Brayan Huamán Pereda
Omar Chirinos García
Docente:
ONOFRE MAYTA PASCUAL FERMIN

2019
Algoritmo de Dijkstra

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, hacia el resto de los vértices en un
grafo que tiene pesos en cada arista.

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 hasta el resto de los nodos.

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 hasta el resto de los vértices que componen el grafo, el algoritmo se
detiene. Se trata de 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ía el costo general del
camino al pasar por una arista con costo negativo).
¿Qué es un grafo?

Un grafo es un tipo de datos abstracto que se utiliza para modelar un conjunto de conexiones. Por
ejemplo, digamos que Bob sigue a Sarah y Lou en Twitter. Sarah sigue a Lin. Lou sigue a Lin y
Mark. Podemos representar estas conexiones utilizando un grafo.

Este grafo ilustra una red de Twitter muy básica.

Cada persona es un nodo y cada conexión es una ventaja. Cada nodo se puede conectar a
muchos otros nodos. Los grafos se pueden dirigir de modo que cada conexión sea unidireccional
como en este ejemplo de Twitter: Bob sigue a Sarah, pero Sarah no sigue a Bob. Los grafos
también pueden no estar dirigidos para que las conexiones se ejecuten en ambos sentidos.
Aplicaciones

En múltiples aplicaciones donde se aplican los grafos, es necesario conocer el camino de menor
costo entre dos vértices dados:

1. Distribución de productos a una red de establecimientos comerciales.


2. Distribución de correos postales.
3. Sea G = (V, A) un grafo dirigido ponderado.

Desarrollo en un Lenguaje de Programación - Javascript

Digamos que está intentando descubrir la forma más económica de llegar a su destino, tal como se
muestra en el gráfico a continuación. Los nodos entre "inicio" y "acabado" son puentes y carreteras
que puede tomar, y los pesos se refieren a los peajes / gasolina que tendrá que pagar.

Nuestro problema que estamos tratando de resolver.

A primera vista, parece que las cosas se pueden volver peludas. Hay muchas rutas diferentes para
evaluar y comparar. Y este gráfico es relativamente simple: ¿qué sucede si encontramos un
problema más complejo con más nodos y posibles rutas?

Pero el algoritmo de Dijkstra toma este problema intimidante y lo descompone, usando unos
simples pasos para llegar a la solución final. El algoritmo de Dijkstra también se adapta bien a este
caso de uso particular. La gráfica utilizada para representar los posibles caminos es dirigida y
acíclica (lo que significa que no hay bucles).
Implementando el grafo

Veamos cómo implementar el grafo en nuestro programa. Usaré un objeto JavaScript anidado:

Cada nodo está representado por las claves en el objeto graph. Cada clave tiene un objeto por su
valor, que representa a los vecinos inmediatos y el costo de alcanzar a ese vecino.

Por ejemplo, el nodo A está conectado a los nodos C y D . El nodo A es el "padre" de los nodos C y
D, y son los "hijos" del nodo A.
Entendiendo el algoritmo

Ahora vamos a delinear los pasos principales en el algoritmo de Dijkstra.

1. Encuentra el nodo “más barato”.


2. Actualizar los costos de los vecinos inmediatos de este nodo.
3. Repita los pasos 1 y 2 hasta que haya hecho esto para cada nodo.
4. Devuelva el costo más bajo para llegar al nodo y la ruta óptima para hacerlo.

Entonces, si estamos comenzando al inicio , los primeros dos nodos que tenemos son A, que tiene
un costo de 5, y B, que tiene un costo de 2. B es el nodo más barato. Estos son los únicos nodos
que conocemos hasta ahora, además del acabado. Y como todavía no sabemos el costo del
acabado , lo estableceremos en Infinity.

Eso ya es mucho de lo que hay que seguir, ¡y solo hemos empezado con el primer nodo! ¿Por qué
no utilizamos una nueva estructura de datos para realizar un seguimiento del costo más bajo para
llegar a cada nodo?

Usaremos un objeto para hacer un seguimiento de esto. Hasta ahora se ve algo como esto:

Pero no solo queremos saber cuánto cuesta alcanzar el nodo final. ¡Queremos saber el camino que
debemos tomar para llegar allí! Esto requiere el uso de otra estructura de datos para realizar un
seguimiento del nodo principal de cada nodo. Cuando un nodo tiene muchos padres posibles, solo
mantendremos el nodo padre que lleva al costo más barato.

Así es como volvemos sobre el camino más barato que se necesita para llegar de principio a fin.
En este momento todavía no sabemos la ruta completa para llegar al nodo final , ya que no
tenemos el padre de finalización.

Tampoco queremos perder el tiempo pasando por los mismos nodos una y otra vez. Queremos
rastrear qué nodos ya se han "procesado". "Procesado" significa que ya hemos calculado el costo
para llegar a cada uno de los hijos del nodo.

Para esto podemos simplemente usar una matriz. Una vez que se haya procesado un nodo, lo
enviaremos a la matriz.

Bien, aquí está la gráfica con la que estamos trabajando otra vez.

Queremos continuar encontrando el nodo más barato y actualizando los costos de esos nodos
hijos. El nodo más barato es B, y sus hijos son A (costo de 8) y D (costo de 7). Los agregamos a
nuestro objeto de costos, que ahora se ve algo así como:
No actualizamos el costo de A , ya que 5 es más barato que 8. Agregamos D con un valor de 9, ya
que el costo para llegar a B es 2, y el costo para llegar a D desde B es 7, por lo que 7 + 2 = 9.

También actualizamos nuestras estructuras de datos procesados y padres . Repetiremos los pasos
anteriores hasta que hayamos procesado todos los nodos.

Implementando el algoritmo

Primero, definiremos una función que, dados los costos y los nodos procesados , devolverá el nodo
más barato que no se haya procesado.

Luego definiremos la función principal, dijkstra , que tomará el gráfico inicial como parámetro.
Comenzaremos creando los costos , los padres y las estructuras de datos procesados .
A continuación, estableceremos el valor inicial del nodo que se está procesando con la función
lowestCostNode . A continuación, vamos a empezar un tiempo de bucle, que se verá de forma
continua durante el nodo más barata.

Aquí hay una descripción de lo que está pasando arriba con mayor detalle:

1. Obtenga el costo del nodo actual


2. Obtenga todos los vecinos (también conocidos como "niños") del nodo actual.
3. Recorra cada uno de los hijos y calcule el costo para llegar a ese nodo hijo. Actualizaremos
el costo de ese nodo en el objeto de costos si es más barato o solo el costo disponible.
4. También actualizaremos la estructura de datos de los padres, para que podamos
volver sobre nuestros pasos al final.
5. Una vez que el nodo esté completamente procesado, lo enviaremos a nuestra
estructura de datos procesados.
6. Restablezca el valor del nodo actual al nodo más barato, sin procesar, y repita.

Finalmente, una vez que se complete el ciclo while, tendremos el costo más bajo para llegar al
nodo final . Ahora queremos obtener la ruta a ese nodo, lo que podemos hacer volviendo sobre
nuestros pasos con el objeto de los padres .

¡Nuestro resultado final debería verse así!


CÓDIGO COMPLETO

const problem = {
start: {A: 5, B: 2},
A: {C: 4, D: 2},
B: {A: 8, D: 7},
C: {D: 6, finish: 3},
D: {finish: 1},
finish: {}
};

const lowestCostNode = (costs, processed) => {


return Object.keys(costs).reduce((lowest, node) => {
if (lowest === null || costs[node] < costs[lowest]) {
if (!processed.includes(node)) {
lowest = node;
}
}
return lowest;
}, null);
};

// Función que devuelve el costo mínimo y la ruta para llegar a Finalizar.


const dijkstra = (graph) => {

// rastrear el menor costo para llegar a cada nodo


const costs = Object.assign({finish: Infinity}, graph.start);

// track paths
const parents = {finish: null};
for (let child in graph.start) {
parents[child] = 'start';
}

// track nodes that have already been processed


const processed = [];

let node = lowestCostNode(costs, processed);

while (node) {
let cost = costs[node];
let children = graph[node];
for (let n in children) {
let newCost = cost + children[n];
if (!costs[n]) {
costs[n] = newCost;
parents[n] = node;
}
if (costs[n] > newCost) {
costs[n] = newCost;
parents[n] = node;
}
}
processed.push(node);
node = lowestCostNode(costs, processed);
}

let optimalPath = ['finish'];


let parent = parents.finish;
while (parent) {
optimalPath.push(parent);
parent = parents[parent];
}
optimalPath.reverse();

const results = {
distance: costs.finish,
path: optimalPath
};

return results;
};

console.log(dijkstra(problem));

Potrebbero piacerti anche