Está en la página 1de 19

145

public String DijkstraPrincipal(E v_origen, E v_destino) {

String camino = "";//camino final que sera devuelto.

LinkedList<E> listtemp = new LinkedList<>();//aqui guardo la lista que

devuelve el metodo al que llamo abajo


listtemp = RutaMasCortaDijkstra(v_origen, v_destino);//para invertir la

lista

//recorrido para crear el string


for (int i = listtemp.size() - 1; i >= 0; i--) {//recorre la lista de

atras para alante


if (camino.isEmpty()) {

camino = listtemp.get(i).toString();//como es el primer

elemento(ultimo en la lista) lo añade.


} else {

camino = camino.concat(", " + listtemp.get(i).toString());

return camino;

public LinkedList<E> RutaMasCortaDijkstra(E v_origen, E v_destino) {

//posVertpadre: va a guardar en el como valor interno la pos del vertice

padre de acuerdo a su posicion(posision en el array es la del vertice hijo y el

valor en esa posicion es la posicion del padre).


int[] posVertPadre = new int[list_vertices.size()];

for (int i = 0; i < posVertPadre.length; i++) {

posVertPadre[i] = -1;

//hago una copia de la matrizpara no modificar la original.


int[][] matrizAdyacentes = new

int[list_vertices.size()][list_vertices.size()];//creo la nueva matriz.


for (int i = 0; i < matriz_adyac.length; i++) {

for (int j = 0; j < matriz_adyac.length; j++) {

matrizAdyacentes[i][j] = matriz_adyac[i][j];

//hago una copia de la lista de vertices para no modificar la original.


LinkedList<Vertice<E>> listVertVisitados = new LinkedList<>();//lista que

sera la de los vertices sin visitar.


for (Vertice<E> i : list_vertices) {

listVertVisitados.add(i);//lista q va a ir eliminando los vertices

que sean visitados


}

LinkedList<E> ruta = new LinkedList<>();//esta lista es la final que

devuelve el camino minimo.

//inicializo todos los valores de la diagonal de la matriz en el valor

mas alto posible


for (int i = 0; i < matrizAdyacentes.length; i++) {

matrizAdyacentes[i][i] = 9999999;

//inicializo el grado del vertice de origen en 0;


matrizAdyacentes[PosVertice(v_origen)][PosVertice(v_origen)] = 0;
BuscarRutaMasCortaR(v_origen, v_destino, matrizAdyacentes,

listVertVisitados, posVertPadre);

ruta = ConstruirCamino(posVertPadre, v_origen, v_destino);//a ruta le

asigno la lista de la ruta que devuelve el metodo.

costoDijkstra =

matrizAdyacentes[PosVertice(v_destino)][PosVertice(v_destino)];//variable creada

en el constructor de la clase, se le asign el costo de dijkstra

// for (int i = 0; i < ruta.size(); i++) {

// for (int j = 1; j < ruta.size(); j++) {


// costoDijkstra = costoDijkstra +

matriz_adyac[PosVertice(ruta.get(j))][PosVertice(ruta.get(i))];
// }

// }

return ruta;

public int[] BuscarRutaMasCortaR(E v_actual, E v_destino, int[][]

matrizAdyacentes, LinkedList<Vertice<E>> listVertVisitados, int[] posVertPadre) {

//FORMULA: Min{L(x),L(v)+w(v,x)}, T{lista de vertices}, V=vertice actual

q se esta visitando
if (v_actual.equals(v_destino) || listVertVisitados.isEmpty()) {

return posVertPadre;//retorna el arreglo

} else {

//declaracion de variables
int suma;//guarda la distancia desde el valor del vertice+peso de la

arista.
int min;//guarda el valor minimo encontrado en la formula

int aux = 9999999;//inicializo la variable en el mayor valor

posible.Guarda el valor de la diagonal principal, para compararlo.


int temp = 0;

//COMENZANDO

//lo siguiente busca en los adyacentes al vertice de origen el de

menor distancia
for (Vertice v : ListVertDestino(v_actual)) {

//ahora suma el valor del vertice q se esta visitando(actual) con

el peso de la arista entre el que se esta visitando y el adyacente actual en que

esta parado el for.


suma =

matrizAdyacentes[PosVertice(v_actual)][PosVertice(v_actual)] +

matrizAdyacentes[PosVertice(v_actual)][v.getPos()];

//busca el minimo entre el vertice q se esta parado en el for y

el de la suma anterior
if (matrizAdyacentes[v.getPos()][v.getPos()] < suma) {

min = matrizAdyacentes[v.getPos()][v.getPos()];
} else {

min = suma;

if (matrizAdyacentes[v.getPos()][v.getPos()] != min) {//control

para q no vuelva adarle el mismo valor y que no cambie el padre


matrizAdyacentes[v.getPos()][v.getPos()] = min;//en la

diagonal de la matriz guarda el grado que va tomando cada vertice, si el valor

actual es mayor lo cambia por el nuevo que es menor.


posVertPadre[v.getPos()] = PosVertice(v_actual);//a la pos

del vertice hijo le asigno la pos del vertice padre(el que le dio el valor)
}

//para eliminar el de a lista de vertices visitados el que ya fue

visitado.
for (Vertice v : list_vertices) {//recorre la lista original de

vertices
if (v.getInfo().equals(v_actual)) {//si el vertice de la lista es

igual al v_actual
for (int i = 0; i < listVertVisitados.size(); i++)

{//comienza recorrido por la lista de vertices visitados

if

(listVertVisitados.get(i).getInfo().equals(v.getInfo())) {//si la info del

vertice en q esta el for es igual a la del q esta el for anterior


listVertVisitados.remove(i);//elimina el vertice de

acuerdo a la pos actual de este for.


break;//rompe el do for, si encontro al vertice

break;//rompe el primer for, si encontro al vertice

// listVertVisitados.remove(PosVertice(v_actual));//como es

visitado lo saco de la lista.

//recorrer la lista de vertices visitados y buscar el de menor grado


y volver a hacer lo mismo hasta que los vertices actual y visitado sean el mismo

o que la lista de visitados este vacia.


for (Vertice v : listVertVisitados) {

if (matrizAdyacentes[v.getPos()][v.getPos()] < aux) {//si es

menor el valor de la pos en la matriz al guardado en aux.


aux = matrizAdyacentes[v.getPos()][v.getPos()];//aux se

actualiza a ese valor


temp = v.getPos();//y guardo la pos del vertice menor

anteriormente guardado en aux.


}

return BuscarRutaMasCortaR(list_vertices.get(temp).getInfo(),

v_destino, matrizAdyacentes, listVertVisitados, posVertPadre);

//la E es para castear.


}

public LinkedList<Vertice> ListVertDestino(E v_origen) {//devuelve una lista

de vertices de destino a uno dado como origen.


LinkedList<Vertice> listdestino = new LinkedList<>();

for (int i = 0; i < matriz_adyac.length; i++) {

if (matriz_adyac[PosVertice(v_origen)][i] != -1) {

listdestino.add(list_vertices.get(i));

return listdestino;

public LinkedList<E> ConstruirCamino(int[] posVertPadre, E v_origen, E

v_destino) {

LinkedList<E> aux = new LinkedList<>();//list q guarda la ruta de atras

para alante
int posVertAnterior = -1;//variable temporal para moverse por el arreglo

de vertices padres
aux.add(v_destino);//añade vertice de destino
return ConstruirCaminoR(posVertPadre, v_origen, v_destino, aux,

posVertAnterior);

//recursivo

public LinkedList<E> ConstruirCaminoR(int[] posVertPadre, E v_origen, E

v_destino, LinkedList<E> aux, int posVertAnterior) {

if (posVertAnterior == PosVertice(v_origen)) {

// aux.add(v_origen);//añade vertice de origen antes de devolverla


return aux;

} else {

posVertAnterior = posVertPadre[PosVertice(v_destino)];//a pospadre le

asigno la pos del vertice adyacente al destino que le dio el valor


aux.add(list_vertices.get(posVertAnterior).getInfo());//añade el

vertice a la lista
return ConstruirCaminoR(posVertPadre, v_origen,

list_vertices.get(posVertAnterior).getInfo(), aux, posVertAnterior);

}
CAMINO MAS CORTO: ALGORITMO DE DIJKSTRA
Publicado el marzo 19, 2012| 59 comentarios
Para el problema de la ruta corta tenemos varios algoritmos, en esta oportunidad se explicará el
algoritmo de dijkstra el cual usa una técnica voraz (greedy). Al final del articulo se encuentran adjuntas
las implementaciones en C++ y JAVA.

Descripción
El algoritmo de dijkstra determina la ruta más corta desde un nodo origen hacia los demás nodos para
ello es requerido como entrada un grafo cuyas aristas posean pesos. Algunas consideraciones:

 Si los pesos de mis aristas son de valor 1, entonces bastará con usar el algoritmo de BFS.
 Si los pesos de mis aristas son negativos no puedo usar el algoritmo de dijsktra, para pesos
negativos tenemos otro algoritmo llamado Algoritmo de Bellmand-Ford.
Como trabaja
Primero marcamos todos los vértices como no utilizados. El algoritmo parte de un vértice origen que
será ingresado, a partir de ese vértices evaluaremos sus adyacentes, como dijkstra usa una técnica
greedy – La técnica greedy utiliza el principio de que para que un camino sea óptim

o, todos los caminos que contiene también deben ser


óptimos- entre todos los vértices adyacentes, buscamos el que esté más cerca de nuestro punto origen, lo
tomamos como punto intermedio y vemos si podemos llegar más rápido a través de este vértice a los
demás. Después escogemos al siguiente más cercano (con las distancias ya actualizadas) y repetimos el
proceso. Esto lo hacemos hasta que el vértice no utilizado más cercano sea nuestro destino. Al proceso
de actualizar las distancias tomando como punto intermedio al nuevo vértice se le conoce
como relajación (relaxation).
Dijkstra es muy similar a BFS, si recordamos BFS usaba una Cola para el recorrido para el caso de
Dijkstra usaremos una Cola de Prioridad o Heap, este Heap debe tener la propiedad de Min-Heap es
decir cada vez que extraiga un elemento del Heap me debe devolver el de menor valor, en nuestro caso
dicho valor será el peso acumulado en los nodos.
Tanto java como C++ cuentan con una cola de prioridad ambos implementan un Binary Heap aunque
con un Fibonacci Heap la complejidad de dijkstra se reduce haciéndolo mas eficiente, pero en un
concurso mas vale usar la librería que intentar programar una nueva estructura como un Fibonacci Heap,
claro que particularmente uno puede investigar y programarlo para saber como funciona internamente.

Algoritmo en pseudocódigo
Considerar distancia[ i ] como la distancia mas corta del vértice origen ingresado al vértice i.

1 método Dijkstra(Grafo,origen):
2 creamos una cola de prioridad Q
3 agregamos origen a la cola de prioridad Q
4 mientras Q no este vacío:
5 sacamos un elemento de la cola Q llamado u
6 si u ya fue visitado continuo sacando elementos de Q
7 marcamos como visitado u
8 para cada vértice v adyacente a u en el Grafo:
9 sea w el peso entre vértices ( u , v )
10 si v no ah sido visitado:
11 Relajacion( u , v , w )

1 método Relajacion( actual , adyacente , peso ):


2 si distancia[ actual ] + peso < distancia[ adyacente ]
3 distancia[ adyacente ] = distancia[ actual ] + peso
4 agregamos adyacente a la cola de prioridad Q
Ejemplo y Código paso a paso
Tengamos el siguiente grafo, cuyos ID están en color negro encima de cada vértice, los pesos esta en
color azul y la distancia inicial en cada vértice es infinito

Algunas consideraciones para entender el código que se explicara junto con el funcionamiento del
algoritmo.

1 #define MAX 10005 //maximo numero de vértices


#define Node pair< int , int > //definimos el nodo como un par( first , second ) don
2 #define INF 1<<30 //definimos un valor grande que represente la distancia infinita i
3 aristas
Inicializamos los valores de nuestros arreglos
Donde:

 Vértices: ID de los vértices.


 Distancia[ u ]: Distancia mas corta desde vértice inicial a vértice con ID = u.
 Visitado[ u ]: 0 si el vértice con ID = u no fue visitado y 1 si ya fue visitado.
 Previo[ u ]: Almacenara el ID del vértice anterior al vértice con ID = u, me servirá para
impresión del camino mas corto.
En cuanto al código los declaramos de la siguiente manera:

1 vector< Node > ady[ MAX ]; //lista de adyacencia


2 int distancia[ MAX ]; //distancia[ u ] distancia de vértice inicial a vértice co
bool visitado[ MAX ]; //para vértices visitados
3 int previo[ MAX ]; //para la impresion de caminos
4 priority_queue< Node , vector<Node> , cmp > Q; //priority queue propia del c++, usam
5 tope
6 int V; //numero de vertices
Y la función de inicialización será simplemente lo siguiente

1
//función de inicialización
2 void init(){
3 for( int i = 0 ; i <= V ; ++i ){
4 distancia[ i ] = INF; //inicializamos todas las distancias con valor infini
5 visitado[ i ] = false; //inicializamos todos los vértices como no visitado
6 previo[ i ] = -1; //inicializamos el previo del vértice i con -1
}
7 }
8
De acuerdo al vértice inicial que elijamos cambiara la distancia inicial, por ejemplo la ruta más corta
partiendo del vértice 1 a todos los demás vértices:

El vértice 1 es visitado, la distancia de vértice 1 -> vértice 1 es 0 por estar en el mismo lugar.

Q.push( Node( inicial , 0 ) ); //Insertamos el vértice inicial en la Cola de Priorid


1 distancia[ inicial ] = 0; //Este paso es importante, inicializamos la distancia
2 0
Extraemos el tope de la cola de prioridad
1 while( !Q.empty() ){ //Mientras cola no este vacia
actual = Q.top().first; //Obtengo de la cola el nodo con menor pe
2 inicial
3 Q.pop(); //Sacamos el elemento de la cola
Si el tope ya fue visitado entonces no tengo necesidad de evaluarlo, por ello continuaría extrayendo
elementos dela cola:

if( visitado[ actual ] ) continue; //Si el vértice actual ya fue visitado entonces s
1 cola
En este caso al ser el tope el inicial no esta visitado por lo tanto marcamos como visitado.

1 visitado[ actual ] = true; //Marco como visitado el vértice actual


Hasta este momento la tabla quedaría de la siguiente manera

Ahora vemos sus adyacentes que no hayan sido visitados. Tendríamos 2 y 4.

1 for( int i = 0 ; i < ady[ actual ].size() ; ++i ){ //reviso sus adyacentes del vertic
adyacente = ady[ actual ][ i ].first; //id del vertice adyacente
2 peso = ady[ actual ][ i ].second; //peso de la arista que une actual con
3 )
4 if( !visitado[ adyacente ] ){ //si el vertice adyacente no fue visitado
Evaluamos primero para vértice 2

Vemos que la distancia actual desde el vértice inicial a 2 es ∞, verifiquemos el paso de relajación:

distancia[ 1 ] + 7 < distancia[ 2 ] -> 0+7<∞ -> 7<∞


El paso de relajación es posible realizarlo entonces actualizamos la distancia en el vértice 2 y agregando
el vértice en la cola de prioridad con nueva distancia quedando:

El paso de relajación se daría en la siguiente parte:

1 for( int i = 0 ; i < ady[ actual ].size() ; ++i ){ //reviso sus adyacentes del vertic
2 adyacente = ady[ actual ][ i ].first; //id del vertice adyacente
3 peso = ady[ actual ][ i ].second; //peso de la arista que une actual con
)
4 if( !visitado[ adyacente ] ){ //si el vertice adyacente no fue visitado
5 relajacion( actual , adyacente , peso ); //realizamos el paso de relajacion
6 }
7 }
Donde la función de relajación seria

1 //Paso de relajacion
2 void relajacion( int actual , int adyacente , int peso ){
3 //Si la distancia del origen al vertice actual + peso de su arista es menor a la
4 adyacente
if( distancia[ actual ] + peso < distancia[ adyacente ] ){
5 distancia[ adyacente ] = distancia[ actual ] + peso; //relajamos el vertice
6 previo[ adyacente ] = actual; //a su vez actualizamo
7 Q.push( Node( adyacente , distancia[ adyacente ] ) ); //agregamos adyacente
8 }
}
9
Ahora evaluamos al siguiente adyacente que es el vértice 4:
De manera similar al anterior vemos que la distancia actual desde el vértice inicial a 4 es ∞,
verifiquemos el paso de relajación:

distancia[ 1 ] + 2 < distancia[ 4 ] -> 0 + 2 < ∞ -> 2<∞


El paso de relajación es posible realizarlo entonces actualizamos la distancia en el vértice 4 quedando:

En cuanto a la cola de prioridad como tenemos un vértice con menor peso este nuevo vértice ira en el
tope de la cola:

Revisamos sus
adyacentes no visitados que serian vértices 2, 3 y 5.
Empecemos por el vértice 2:
Ahora vemos que la distancia actual del vértice inicial al vértice 2 es 7, verifiquemos el paso de
relajación:

distancia[ 4 ] + 3 < distancia[ 2 ] -> 2 + 3 < 7 -> 5<7


En esta oportunidad hemos encontrado una ruta mas corta partiendo desde el vértice inicial al vértice 2,
actualizamos la distancia en el vértice 2 y actualizamos el vértice previo al actual quedando:

En cuanto a la cola de prioridad como tenemos un vértice con menor peso este nuevo vértice ira en el
tope de la cola, podemos ver que tenemos 2 veces el mismo vértice pero como usamos una técnica
greedy siempre usaremos el valor óptimo:

Continuamos
con los Vértices 3 y 5 como tienen valor ∞ si será posible relajarlos por lo que sería similar a los pasos
iniciales solo que en los pasos iniciales distancia[ 1 ] era 0 en este caso distancia[ 4 ] es 2, quedando:
Hemos
terminado de evaluar al vértice 4, continuamos con el tope de la cola que es vértice 2, el cual marcamos
como visitado.

Los adyacentes
no visitados del vértice 2 son los vértices 3 y 5. Comencemos con el vértice 3
Ahora vemos que la distancia actual del vértice inicial al vértice 3 es 10, verifiquemos el paso de
relajación:

distancia[ 2 ] + 1 < distancia[ 3 ] -> 5 + 1 < 10 -> 6 < 10


En esta oportunidad hemos encontrado una ruta mas corta partiendo desde el vértice inicial al vértice 3,
dicha ruta sería 1 -> 4 -> 2 -> 3 cuyo peso es 6 que es mucho menor que la ruta 1 – > 4 -> 3 cuyo peso es
10, actualizamos la distancia en el vértice 3 quedando:

El siguiente
vértice de la cola de prioridad es el vértice 3 y su único adyacente no visitado es el vértice 5.
Vemos que la
distancia actual del vértice inicial al vértice 5 es 7, verifiquemos el paso de relajación:
distancia[ 3 ] + 5 < distancia[ 5 ] -> 6 + 5 < 7 -> 11 < 7
En esta oportunidad se no cumple por lo que no relajamos el vértice 5, por lo que la tabla en cuanto a
distancias no sufre modificaciones y no agregamos vértices a la cola:

Ahora tocaría el vértice 2 pero como ya fue visitado seguimos extrayendo elementos de la cola, el
siguiente vértice será el 5.

Al ser el ultimo
vértice a evaluar no posee adyacentes sin visitar por lo tanto hemos terminado el algoritmo. En el grafico
anterior observamos que 2 aristas no fueron usadas para la relajación, las demás si fueron usadas. La
tabla final quedaría de la siguiente manera:

De la tabla si deseo saber la distancia mas corta del vértice 1 al vértice 5, solo tengo que acceder al valor
del arreglo en su índice respectivo (distancia[ 5 ]).
Shortest Path Tree
En el proceso anterior usábamos el arreglo previo[ u ] para almacenar el ID del vértice previo al vértice
con ID = u, ello me sirve para formar el árbol de la ruta mas corta y además me sirve para imprimir
caminos de la ruta mas corta.

Impresión del camino encontrado.


Para imprimir el camino mas corto deseado usamos el arreglo previo[ u ], donde u tendrá el ID del
vértice destino, o sea si quiero imprimir el camino mas corto desde vértice 1 -> vértice 3 partiré desde
previo[ 3 ] hasta el previo[ 1 ]. De manera similar a lo que se explico en el algoritmo BFS, en este caso
se realizara de manera recursiva:

1 //Impresion del camino mas corto desde el vertice inicial y final ingresados
2 void print( int destino ){
3 if( previo[ destino ] != -1 ) //si aun poseo un vertice previo
4 print( previo[ destino ] ); //recursivamente sigo explorando
5 printf("%d " , destino ); //terminada la recursion imprimo los vertices re
}
6
Veamos gráficamente el funcionamiento, desde el grafo comenzamos en 3
El previo de 3 es el vértice 2, por lo tanto ahora evaluó 2:

Ahora el previo de 2 es el vértice 4:


El previo de 4 es el vértice inicial 1

Como el previo de 1 es -1 terminamos el recorrido, ahora en el retorno de las llamadas recursivas


imprimo el camino: 1 4 2 3

También podría gustarte