Está en la página 1de 8

Estructuras de Datos y Algoritmos II curso 2019-2020

Conferencia # 04: “Algoritmos para la búsqueda de caminos mínimos. Caminos mínimos en


grafos sin pesos y con pesos positivos”
búsqueda de caminos mínimos en grafos sin pesos
búsqueda de caminos mínimos en grafos con pesos positivos (Algoritmo de Dijsktra)

BIBLIOGRAFÍA
1- Estructuras de Datos en Java, Mark Allen Weiss, Volumen II, Tercera parte. Capítulo 14,
epígrafes 14.2 y 14.3 páginas de 366 a la 376.
2- Estructuras de Datos, Algoritmos y Programación Orientada a Objetos, Gregory L.
Heileman, Capítulo 14, epígrafe 14.4 páginas de 258 a la 261.
3- Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, and Ronald L.
Rivest, Parte VI. (en format digital)
(\\10.12.1.64\docs\MFC\Docencia\Materiales Docentes\Pregrado\Computacion\07-
Programacion e Ingenieria de Software\EDA II\13-14\02- MaterialesComplementarios\ 01-
Introduction to Algorithms 3rd Edition)\ 01- Introduction to Algorithms 3rd Edition )

Elementos de la clase anterior


- Un grafo G = G (V, A) está formado por un conjunto no vacío de vértices V y un conjunto de
aristas A. Cada arista es un par <v, w>, donde v, w  V. Algunas veces, las aristas tienen una
tercera componente, denominada peso o costo. Un grafo puede ser dirigido (directed) o no
dirigido (undirected). A un grafo dirigido se le llama digrafo. Los Vértices se denominan
también nodos y son objetos que pueden tener nombre y otras propiedades. Las Aristas se
denominan también arcos y son conexiones entre dos vértices y representan relaciones entre
los objetos.
- Se utilizarán la representación para Grafos en Matriz de Adyacencia y en Listas de
Adyacencia. La primera es más adecuada para grafos densos y la segunda es mejor para grafos
dispersos.
- En la implementación del TDA Grafo trabajaremos con una interface Grafo que define
las operaciones básicas que estudiaremos de Grafo (se modifica durante el curso en la medida
que avancemos) y con las clases GrafoListaAdyacencia,
GrafoMatrizAdyacencia, Vertice y Arista que también pueden irse modificando
en la medida que avance el curso.
- Los grafos pueden recorrerse siguiendo dos estrategias primero a lo ancho y primero en
profundidad. Estos dos recorridos de grafo se adicionan a la interfaz Grafo y deben ser
implementados según la representación usada.
Ejemplo de recorrido primero a lo ancho comenzando en V1 (las flechas indican el orden en
que se realiza el recorrido) y árbol de expansión.
V2
1 2 V6
V1
V3
V1 0 1 2 V7

V2 V3 V4 V5
1 2 V8
V4 V9
V6 V7 V8
V5 1 2 V9

1
Estructuras de Datos y Algoritmos II curso 2019-2020

Algoritmos de búsqueda de caminos mínimos


El problema de la búsqueda de caminos mínimos consiste en calcular, dado un vértice de origen,
los caminos mínimos desde este punto a todos los demás vértices (o a un vértice específico en
particular).

Cuando el grafo es no es ponderado (las aristas no tienen peso) el camino mínimo se puede
considerar como aquel que conecta al vértice origen con cada uno de los restantes vértices a través
de un menor número de aristas.
Por ejemplo:
El grafo anterior, aunque no es dirigido (cada
V1 arista conecta en ambas direcciones) puede
servir para analizar una solución.
Supongamos que el vértice origen es V7
V2 entonces: ¿cuáles serían los caminos mínimos
V3
1 al resto de los vértices de ese grafo partiendo
1
de V7?
V4 Los adyacentes V3 y V8 tendrían camino
V5 V6 V7 mínimo igual a 1 (cantidad de aristas
V1
1 1 1
necesarias para conectarlo con el origen) y
luego los adyacentes de V3 y V8 tendrían
V8 caminos mínimos igual a 2 y así
1 sucesivamente…

Cuando el grafo es ponderado (las aristas tienen peso) el problema es diferente, pues el camino
mínimo es aquel que la suma de los pesos de las aristas que lo integran sea mínima.

V1
3 4
En este ejemplo si el vértice origen es V7,
V2
4 1
V3 3 entonces el camino mínimo para V8 es V7,
3 2 1 V3, V6, V8 que suma 7 y no V7, V8 porque
suma 8, aunque tiene un menor número de
V4 aristas.
V5 V6 V7
V1 2
1 2 1 1
10 8

V8
1
Entonces las estrategias de los algoritmos que dan solución a estas problemáticas son diferentes.

Antes de comenzar a estudiar esos algoritmos adicionemos dos atributos a la clase Vertice para
que estos algoritmos puedan funcionar adecuadamente:
dist: Este valor es calculado por el algoritmo de búsqueda del camino mínimo. Tendrá la
longitud/distancia del camino más corto desde el vértice de origen hasta este vértice.
ant: Este valor también es calculado por el algoritmo de búsqueda del camino mínimo. Indicará
el vértice anterior en el camino más corto a este vértice. Retrocediendo por este campo vamos

2
Estructuras de Datos y Algoritmos II curso 2019-2020

construyendo el camino mínimo. Aunque esta traza nos da el camino en orden inverso, es fácil
invertirlo si se utiliza la recursividad.
Estos nuevos atributos se adicionan en la clase Vertice y No en VerticeExt .

Recordar que el vértice ya tenía dos atributos:


nombre : el nombre correspondiente a este vértice. Se fija cuando el vértice se inserta en el
arreglo tabla y no cambiará nunca. Sólo se utiliza al imprimir el camino final.
extra: es el atributo que adicionamos para conocer si un vértice es visitado o no en los
recorridos de un grafo (amplitud y profundidad), recordemos que lo declaramos de tipo entero
(simulando un atributo booleano tomando valores 0 y 1) porque para otros algoritmos usaremos
este mismo atributo como un contador, y de esta manera no tenemos que tener tantos atributos
declarados en la clase innecesariamente.

Los algoritmos de búsqueda del camino mínimo que estudiaremos corresponden a un único
origen . Es decir, todos suponen un punto de origen y calculan los caminos mínimos desde este
punto a todos los demás vértices.

Problema de los caminos mínimos sin pesos.


La longitud del camino sin pesos mide el número de aristas. El problema entonces consiste en
“Encontrar los caminos más cortos (medidos por el número de aristas) desde el vértice origen O al
resto de los vértices”.
El problema de caminos mínimos sin pesos es un caso especial del problema de caminos mínimos
con pesos, asumiendo que todos los pesos valen 1. Por tanto, debemos tener una solución más
eficiente que la del problema con pesos.
Consideremos el siguiente grafo, con V2 como nodo origen (O) y analicemos cómo encontrar la
longitud de los caminos mínimos.
V V
0 1

V V V
2 3 4

V V
5 6
Es evidente que el camino más corto desde O a V2 es un camino de longitud 0. Ahora podemos
mirar los nodos que están a distancia 1 de O, es decir los que son adyacentes a V2 (V0 y V5).
El siguiente paso es buscar los vértices cuyo camino desde O sea exactamente 2. Hacemos esto
buscando los nodos adyacentes a V0 y V5, es decir los que están a distancia 1, y cuyo camino
mínimo no se conozca aún. Esta búsqueda nos dice que el camino más corto a V1 y V3 es 2.
Finalmente, examinando los vértices adyacentes a los últimamente alcanzados V1 y V3,
encontramos que V4 y V6 tienen un camino mínimo de 3 aristas. Y ya hemos calculado el camino
para todos los vértices.

3
Estructuras de Datos y Algoritmos II curso 2019-2020

1 2
V V
0 1
0
2 3
V V V
2 3 4
1
3
V V
5 6
Hemos seguido la estrategia de búsqueda en anchura. Los vértices más cercanos al origen se
procesan los primeros y los más alejados los últimos.

La siguiente figura muestra un principio fundamental: Si un camino al vértice v tiene costo Dv, y
w es adyacente a v, entonces existe un camino a w de costo Dw = 1 + Dv
Dv 1+ Dv
v w

0
O

Todos los algoritmos de búsqueda de caminos mínimos empiezan en Dw = ∞ y van reduciendo


este valor cuando se explora un vértice v apropiado.

Algoritmo de caminos mínimos en grafos sin pesos:


Dado un vértice inicial s.
1. Se inicializan las distancias de todos los vértices en infinito, y el atributo anterior de todos
los vértices en -1.
2. Se inicializa la distancia de s en cero, se inserta a s en la cola.
3. Mientras la cola no este vacía:
Se quita el primero de la cola y se toma como vértice actual v.
Para cada vecino w del vértice actual v:
Si ese vecino tiene distancia igual a infinito entonces
Se actualiza la distancia (Dw = Dv +1)
Se actualiza el vértice anterior (para guardar el recorrido)
Se pone el vecino w en la cola
4. Fin.

Hay dos acciones básicas a realizar:


1ro. Buscar repetidamente el vértice que se analiza.
2do. Comprobar todos los vértices w adyacentes a v (el vértice actual)
Un análisis de la complejidad de estas operaciones usando una representación de grafo sobre lista
de adyacencia (ver página 368 de bibliografía 1 de la conferencia).

La segunda acción se implementa fácilmente iterando dentro de la lista de vértices adyacentes a v.


Como cada arista se procesa una vez, el costo total es O(│A│).

4
Estructuras de Datos y Algoritmos II curso 2019-2020

La primera acción es más complicada, no podemos limitarnos a explorar la tabla buscando el


vértice apropiado, pues cada exploración requeriría un tiempo O(│V│) y necesitamos hacerlo
O(│V│) veces y, ese tiempo O(│V│2 ), es inaceptable para grafos dispersos.
Cuando a un vértice w se le rebaja su Dw desde ∞, se convierte en candidato para fijar nuestra
atención en él en algún momento del futuro. Una vez que hayamos fijado nuestra atención en
todos los vértices que se encuentran a igual distancia del origen, Dv, que el actual, pasaremos a
considerar los que se encuentran a distancia Dv + 1, entre los que se encuentra w. Por lo que a w
sólo le queda esperar pacientemente su turno en una cola.
Comenzamos con una cola vacía y colocamos en la cola el vértice origen O. Ya que cada vértice se
introduce en la cola y se elimina de ella exactamente una vez, y ya que las operaciones sobre las
colas son constantes, el costo total de elegir un vértice para el algoritmo completo es O(│V│). Por
tanto, el costo de la búsqueda a lo ancho está dominado por los recorridos de las listas de
adyacencias, y en consecuencia es O(│A│), o sea lineal con respecto al tamaño del grafo.

Algoritmo de Dijkstra para obtener caminos mínimos con pesos positivos.


La longitud de un camino con pesos es la suma del costo de las aristas del camino. En el problema
de los caminos mínimos con pesos positivos, las aristas tienen costos no negativos. Queremos
calcular los caminos mínimos desde un vértice origen al resto de los vértices. El método que
veremos se conoce con el nombre de algoritmo de Dijkstra.
El caso anterior, el problema sin pesos, es un caso particular de este, considerando todos los pesos
igual a 1; por tanto, su solución debe ser semejante, pero debemos tener en cuenta lo siguiente:
1. ¿Cómo se ajusta Dw?
Analicemos la siguiente situación:
3
3 8
v w

0
6
O 2

u
Cuando se analizó el vértice u, se rebajó la distancia a w a 8. Ahora, al analizar el vértice v,
necesitamos volver a cambiar la distancia a w, rebajándola a 6, pues tenemos un nuevo
camino mínimo -provisional. Esto no sucedía en el camino sin pesos. Aquí, aunque Du  Dv,
es todavía posible que el camino a w se mejore al considerar v. Por otra parte, cuando se
rebaja la distancia a w, es siempre porque es adyacente a algún vértice en el que hemos fijado
nuestra atención. Por ejemplo, después de haber visitado a v y completado su procesamiento,
el valor de Dw será 6 y el último vértice en el camino será un nodo ya visitado. De forma
análoga, el vértice anterior a v debe haberse visitado, y así sucesivamente. Por tanto, en
cualquier momento, el valor de Dw representa un camino desde O hasta w utilizando como
nodos intermedios solamente vértices que ya han sido visitados. Esto lleva al siguiente teorema (pág.
372).
Teorema. Si vamos pasando nuestra atención a un vértice aún no visitado de entre los que
minimicen el valor Di, el algoritmo de Dijkstra producirá correctamente los caminos mínimos
siempre que no haya aristas con costo negativo.

2. ¿Cómo buscamos el siguiente vértice v en el que centrar nuestra atención?

5
Estructuras de Datos y Algoritmos II curso 2019-2020

Es evidente que debamos buscar el vértice v con menor Dv. Esto sugiere el uso de una Cola de
prioridad. El método consistirá en insertar en la cola de prioridad -cuando reducimos Dw- un
objeto formado por w y como prioridad el valor de Dw. Para elegir el nuevo vértice v a visitar,
eliminaremos repetidamente el menor elemento (utilizando las distancias) hasta que salga un
elemento no visitado. Necesitaremos entonces una marca que indique si ha sido o no visitado.
Como el tamaño de la cola será, a lo sumo, A y se realizarán como mucho A inserciones y
eliminaciones, el tiempo de ejecución será O(AlogA).

Analicemos el algoritmo mediante un ejemplo:


Tomemos en el siguiente gráfico al vértice 0
V0 como inicial; por tanto, su costo mínimo V 2 V
será 0: 0 1
4 1 10
3
V 2 V 2 V
2 3 4

5 8 4 6

V 1 V
5 6

Marcamos a V0 como visitado y recorremos 0


2
su lista de adyacencia, calculando los costos V 2 V
de sus vértices adyacentes y colocándolos en 0 1
la cola de prioridad (CdeP): (2, V1) y (1, 4 1
1 3 10
V3):
V 2 V 2 V
2 3 4

5 8 4 6

V 1 V
5 6

Se extrae de la CdeP a (1, V3) se marca V3 0


2
como visitado y se recorre su lista de V 2 V
adyacencia, guardando en la CdeP a (3, V4), 0 1
(9, V5), (3, V2) y (5, V6): 4 1
3 1 3 10 3
V 2 V 2 V
2 3 4

5 8 4 6
9 5
V 1 V
5 6

6
Estructuras de Datos y Algoritmos II curso 2019-2020

Se extrae de la CdeP a (2, V1), se marca V1 0


2
como visitado y se recorre su lista de V 2 V
adyacencia; no se guarda nada en la CdeP 0 1
porque ni a V4 ni a V3 se le alteran sus Dw: 4 1
3 1 3 10 3
V 2 V 2 V
2 3 4

5 8 4 6
9 5
V 1 V
5 6

Así sucesivamente se aplica el algoritmo hasta que en la última iteración:


Se extrae de la CdeP a (8, V5), se comprueba 0
2
que V5 está marcado. Se extrae de la CdeP a V 2 V
(9, V5), se comprueba que V5 está marcado. 0 1
La CdeP está vacía, ¡fin del proceso! 4 1
3 1 3 10 3
SE obtiene finalmente:
V 2 V 2 V
2 3 4

5 8 4 6
6 5
V 1 V
5 6

ESTUDIAR por el libro “Estructuras de Datos en Java” el ejemplo anterior, según las indicaciones de la
bibliografía de esta Conferencia. Allí podrá encontrar también una implementación en Java de los
algoritmos estudiados en esta actividad.

Algoritmo de caminos mínimos en grafos con pesos positivos (Dijkstra)


Obtención de caminos mínimos en un grafo con pesos positivos, partiendo de un vértice origen que
llamamos s.
P1: Inicializar toda la información de los vértices (dist=INFINITO; extra=0; ant=-1)
P2: Colocar dist(s)=0
P3: Inicializar la cola de prioridad CP, e insertar en ella a s/0
P4: mientras CP != vacío hacer
P4.1: u = CP.eliminarMin()
P4.2: Si u ya está marcado como visitado entonces CONTINUAR (ir a P4)
P4.3: Visitar u (marcarlo como visitado)
P4:4: Para todo vértice w adyacente a u hacer
P4.4.1: Si c(u,w)<0 entonces TERMINAR por error
P4.4.2: Si dist(w) > dist(u)+c(u,w) entonces hacer
P4.4.2.1: dist(w)=dist(u)+c(u,w)
P4.4.2.2: ant(w)=u
P4.4.2.3: CP.insertar(w/dist(w))
P5: TERMINAR ok.

7
Estructuras de Datos y Algoritmos II curso 2019-2020

CONCLUSIONES

RESUMEN
/*
* Interface TDA Grafo, version 1.2
*/
public interface Grafo {

//manipulación del grafo


int insVertice(String nombre);
void insArista(String origen, String destino, float peso);
void insArista(String origen, String destino);
void elimVertice(String nombre);
void elimArista(String origen, String destino);

int buscarVertice(String nombre);


boolean esAdyacente(String origen, String destino);

//recorridos sobre grafos


List recorridoAmplitud(String VerticeOrigen);
List recorridoProfundidad(String VerticeOrig);

//caminos mínimos
void caminoMSinPeso(String VerticeOrigen);
boolean caminoMConPesoPositivo(String VerticeOrigen);

También podría gustarte