Sei sulla pagina 1di 10

Tema 15 - Soluciones Greedy para Problemas de

Optimizacin sobre un Grafo

ndice general:
1. Caminos Mnimos en un Grafo sin Pesos
Tema 15 - Soluciones Greedy 2. Caminos Mnmos en un Grafo ponderado
para Problemas de Optimizacin 1. Algoritmo de Dijkstra
sobre un Grafo 3. Ordenacin Topolgica
4. Algoritmos para obtener el rbol generador mnimo
1. Algoritmos de Prim y Kruskal
Germn Molt
Escuela Tcnica Superior de Ingeniera Informtica
Universidad Politcnica de Valencia

1 2

Bibliografa Caminos Mnimos en un Grafo


Libro de M.A. Weiss, Estructuras de Datos en Java (Adisson- El problema del clculo de los caminos mnimos en un Grafo
Wesley, 2000). es de gran inters dado que muchas aplicaciones reales pueden
Captulo 22, apartado 22.2.3 para el algoritmo de Dijkstra con modelarse mediante esta estructura de datos.
Montculos de Emparejamiento Obtencin de la ruta ms rpida entre dos puntos.
Gestin de paquetes en una red de computadores.
Variantes del problema:
Clculo del camino mnimo en Grafos sin pesos y en Grafos con
pesos. El camino mnimo en un grafo ponderado NO tiene porqu
ser el camino ms corto. 2
3
1 2 v1 v2 v3
3 8
7 7 7
3
5 4 v4 v5 v6
Grafo sin pesos: 3
Camino mnimo en n de aristas Grafo con pesos:
3 4 Camino mnimo considerando pesos
Problema del Camino Mnimo Sin Pesos Problema del Camino Mnimo Sin Pesos
con nico Origen (I) con nico Origen (II)
Encontrar el camino ms corto (medido en n de aristas) Para obtener los vrtices cuyo camino mnimo desde el
desde un vrtice origen a cualquier otro vrtice. vrtice origen tiene longitud k nos apoyamos en los nodos
El problema del camino sin pesos es un caso particular del adyacentes cuyo camino desde el vrtice origen es k-1.
camino con pesos donde todos los pesos valen 1. En realidad estamos realizando un recorrido en anchura,
b c d donde los vrtices ms cercanos al vrtice origen se procesan
aa i e antes que los ms alejados, trabajando por niveles.
1 2
h g f v0 v1
Vrtice Origen: a Vrtice Origen:V2
0 3
Nodos a distancia 0 de a {a} 2 Nodos a distancia 0 de V2 {V2}
v2 v3 v4
Nodos a distancia 1 de V2 {V0,V5}
Nodos a distancia 1 de a {b, h} (adyacentes a los de dist. 0)
Nodos a distancia 2 de V2 {V1,V3}
Nodos a distancia 2 de a {c, i, g} (adyacentes a los de distancia 1 v5 v6
Nodos a distancia 3 de V2 {V4,V6}
1) 3

5 6

Reformulacin del BFS para el Clculo Traza de Camino Mnimo Sin Pesos
del Camino Mnimo Sin Pesos (distanciaMin)

Recorrido en Anchura o Breadth First Search (BFS) del Vrtice origen:V2 Vertices distanciaMin
Vrtice dado, vOrigen, en el que visitados pasa a ser 0 1 2 3 4 5 6
v0 v1
distanciaMin. 2 | q = 2| q = 0
- - - - - -
distanciaMin[i] representa la Distancia mnima desde el Vrtice 2| q = 0 , 5 1- - - - - 1 -
vv2 v3 v4 0| q = 5 , 1 , 3 2 2
dado vOrigen al Vrtice i. - - - - - -
5| q = 1 , 3 - - - - - -
distanciaMin[vOrigen] == 0 1| q = 3 , 4 - - - - 3- - -
v5 v6
si distanciaMin[i] == el Vrtice i no se ha visitado an - - - - - - -
- - - - - - -
si distanciaMin[i] != el Vrtice i s se ha visitado, desde un como distanciaMin[3] != - - - - - - -
cierto vrtice vAnterior: NO cambia su valor a 3 1 2 0 2 3 1
distanciaMin[i]=distanciaMin[vAnterior]+1
De esta manera el algoritmo controla los vrtices que ya han
sido visitados anteriormente. Aunque en esta traza los
vrtices se numeren de 0..N, de
normal los numeramos de 1..N
7 8
Traza de Camino Mnimo Sin Pesos Traza de Camino Mnimo Sin Pesos
(distanciaMin): Tabla Final (caminoMin)
Vrtice distanciaMin Cola Para guardar el camino, utilizamos un vector llamado
1 2 3 4 5 6 7 caminoMin:
caminoMin[i] == -1 si el Vrtice i an NO es del Camino Mnimo.
0 3 caminoMin[i] == vAnterior si el Vrtice i se alcanza desde
3: 1 6 1 0 1 16 vAnterior en el Camino Mnimo.
Vertices distanciaMin caminoMin
1: 2 4 1 2 0 2 1 624
0 1 2 3 4 5 6 0 1 2 3 4 5 6
6: 1 2 0 2 1 24 v0 v1 2 | q =2| 0 -1 -1 -1 -1 -1 -1 -1
2: 4 5 1 2 0 2 3 1 45 2 | q =0 1 - - - - - - -2 - - - - - -
2 | q =0, 5 - - - - - 1 - - - - - - 2- -
4: 3 5 6 7 1 2 0 2 3 1 3 57 v2 v3 v4 0 | q =5, 1 - 2 - - - - - - -0 - - - - -
5: 7 1 2 0 2 3 1 3 7 0 | q =5, 1, 3 - - - 2 - - - - - - 0- - - -
v1 v2 5 | q =1, 3 - - - - - - - - - - - - - -
7: 6 1 2 0 2 3 1 3 v5 v6 1 | q =3, 4 - - - - 3 - - - - - - 1- - -
3 | q =4, 6 - - - - - - 3 - - - - - - 3-
v3 v4 v5 4 | q =6 - - - - - - - - - - - - - -
6|q= - - - - - - - - - - - - - -
9 1 2 0 2 3 1 3 2 0 -1 0 1 2 3
v6 v7 10

Traza de Camino Mnimo Sin Pesos Ampliacin de la clase Grafo para


(caminoMin): Tabla Final Caminos Mnimos sin Pesos (I)
package librerias.estructurasDeDatos.grafos;
Vrtice distanciaMin caminoMin Cola
public abstract class Grafo<E> {
1 2 3 4 5 6 7 1 2 3 4 5 6 7

0 -1 -1 -1 -1 -1 -1 -1 protected static final int INFINITO = (Integer.MAX_VALUE) / 3;
3: 1 6 1 01 3 -1 -1 -1 -1 3 -1 16 protected int distanciaMin[];
1: 2 4 1 2 0 21 3 1 -1 1 -1 3 -1 624 protected int caminoMin[];
6: 1 2 0 21 3 1 -1 1 -1 3 -1 24
public void caminosMinimoSinPesos(int vOrigen) {
2: 4 5 1 2 0 2 3 1 3 1 -1 1 2 3 -1 45
distanciaMin = new double[numVertices() + 1];
4: 3 5 6 7 1 2 0 2 3 1 3 3 1 -1 1 2 3 4 57 caminoMin = new int[numVertices() + 1];
5: 7 1 2 0 2 3 1 3 3 1 -1 1 2 3 4 7 for (int i = 1; i <= numVertices(); i++) {
v1 v2 distanciaMin[i] = INFINITO;
7: 6 1 2 0 2 3 1 3 3 1 -1 1 2 3 4 caminoMin[i] = -1;
v3 v4 v5 }

11v6 v7 12
Ampliacin de la clase Grafo para
Caminos Mnimos sin Pesos (II) Camino Mnimo con Pesos

q = new ArrayCola<Integer>(); Problema de los Caminos Mnimos con Coste Positivo
q.encolar(new Integer(vOrigen)); distanciaMin[vOrigen] = 0; y Orgen nico:
while (!q.esVacia()) { Encontrar el camino de longitud ms corta (considerando los
int v = q.desencolar().intValue(); pesos) desde el vrtice origen al resto de vrtices.
ListaConPI<Adyacente> aux = adyacentesDe(v); El coste de cada arista debe ser positivo.
aux.inicio(); La longitud de un camino con pesos es la suma del coste de
while (!aux.esFin()) { las aristas del camino.
int w = aux.recuperar().destino;
if (distanciaMin[w] == INFINITO) { // w no visitado an El mtodo del clculo del camino mnimo en un Grafo sin
distanciaMin[w] = distanciaMin[v] + 1; pesos NO es directamente aplicable a este problema.
caminoMin[w] = v; q.encolar(new Integer(w));
}
aux.siguiente(); } } }
13 14

Problema al Usar Algoritmo de Camino Adaptacin del Recorrido de la Lista de


Mnimo Sin Pesos a un Grafo Ponderado Adyacentes a un Vrtice
2
v0 v1 Vertices distanciaMin
while ( !aux.esFin() ) {
4 10 0 1 2 3 4 5 6 Adyacente a = aux.recuperar();
4 1
2 | q = 2| q = 0
v22 v3 v4 int w = a.destino, costeW = a.peso;
2 2|q=0 4 - - - - - -
8 4 2 if ( distanciaMin[w] > distanciaMin[v] + costeW ) ) {
2 | q = 0, 5 - - - - - 5 -
5 6 0 | q = 5, 1 - 6 - - - - -
v5 v6 distanciaMin[w] = distanciaMin[v] + costeW;
1 0 | q = 5, 1, 3 - - - 8 - - -
5 | q = 1, 3 - - - - - - - caminoMin[w] = v; q.encolar(new Integer(w));
- - - - - - -
distanciaMin[3] == 8 NO }
- - - - - - -
cambia a 7, porque solo - - - - - - - aux.siguiente();
1 |q = 3
comprueba INFINITO! 4 6 0 8 - 5 - }
El algoritmo de camino mnimo sin pesos slo actualiza el Ahora se comprueba si se ha encontrado un camino de mejor
contenido de distanciaMin si distanciaMin[i] == INFINITO, no coste y se actualizan los vectores distanciaMin y caminoMin.
considera el hecho de haber encontrado un camino ms corto Problema: Es posible que en la cola introduzcamos vrtices ya
(considerando pesos). visitados!
15 16
Problema Adicional en la Gestin de la
Cola Reformulacin de la Cola Empleada
2 Vertices distanciaMin Los datos de la Cola ya no sern Integer, sino Pares de Integer
v0 v1 0 1 2 3 4 5 6
4
(adyacente, coste global de llegar a l desde el vrtice origen). En
10 2 | q = 2| q = 0
4 1
2 |q=0 4 - - - - - -
el ejemplo, se encolaran: (2,0), (0,4), (5,5), (1,6), (3,8), (3,7).
v22 v3 v4
2 8 4 2 2 | q = 0, 5 - - - - - 5 - Cambios a realizar:
0 | q = 5, 1 - 6 - - - - -
5 6
0 | q = 5, 1, 3 - - - 87 - - - Aadir la clase DistanciaHastaV (que representa un par) a la
v5 v6
1 5 | q = 1, 3 - - - - - - - estructura de clases actual.
1 | q = 3 ,3 - - - - - - - q.encolar(new Integer(vOrigen))q.encolar(new DistanciaHastaV
!!! NO se puede usar una - - - - - - -
(vOrigen,0))
- - - - - - -
simple Cola de Integer !!! 4 6 0 87 - 5 - q.encolar(new Integer(w)) q.encolar(new DistanciaHastaV (w,
distanciaMin[w]))
Para evitar introducir en la Cola elementos repetidos, Los Pares de Integer se ordenan por Distancia, por lo que la
tendremos que diferenciar entre haber llegado a un adyacente
Cola pasa a ser una Cola de Prioridad, implementada como un
por una arista o por otra.
Heap. En el ejemplo, (3,7) se colocar ANTES de (3,8).
La diferencia se establecer en base al coste de la arista.
17 18

Uso de Cola de Prioridad en Problema de


Caminos Mnimos con Pesos Gestin de Vrtices Repetidos
2 Hay que marcar los Vrtices ya visitados para no volverlos a
v0 v1 Vertices distanciaMin
0 1 2 3 4 5 6
procesar :
4 10
4 1 2|qP=(2,0) 0 Sin este mecanismo, en el ejemplo anterior procesaramos el
v22 v3 v4 2|qP=(0,4) 4 - - - - - -
2 2|qP=(0,4),(5,5) - - - - - 5 - vrtice 3 dos veces: (3,7), (3,8).
8 4 2
0|qP=(5,5),(1,6) - 6 - - - - -
5 6 0|qP=(5,5),(1,6),(3,8) - - - 7
8 - - -
nicamente interesa procesar el par por el cual se incurre en
v5 v6
1
5|qP=(1,6),(3,8) - - - - - - - un coste menor y eso lo controla la Cola de Prioridad.
(4,16)
(3,7) 1|qP=(3,7)
1|qP=(3,8) ,(3,8)
1|qP=(3,7),(3,8) - - - - - - -
1|qP=(3,7),(3,8),(4,16)
1|qP=(3,7),(3,8),(4,16) - - - - 9 - - Este mecanismo nos permite evitar procesar vrtices ya
3|qP=(3,8),(4,9),(4,16) procesados anteriormente.
3|qP=(3,8),(4,10),(4,16),(6,11) 11
Utilizamos un atributo para marcar los Vrtices ya visitados:
- - - - - - - si visitados[i] == 0, el Vrtice i NO se ha visitado an
4 6 0 87 9 5 - si visitados[i] == 1, el Vrtice i S se ha visitado
Hay que marcar los Vrtices ya desencolados para no
volverlos a procesar: (3,7), (3,8).
19 20
Traza Completa de Camino Mnimo con Cola de Ampliacin de la Clase Grafo para
Prioridad Caminos Mnimos con Pesos
Vrtice distanciaMin visitados Cola de Prioridad public abstract class Grafo<E> {
1 2 3 4 5 6 7 1 2 3 4 5 6 7
0 0 0 0 0 0 0 0 (3,0) protected ColaPrioridad<DistanciaHastaV> qPrior;
3: 1 6 4 05 0 0 1 0 0 0 0 (1,4), (6,5)
1: 2 4 4 6 0 8 5 1 0 1 0 0 0 0 (6,5), (2,6), (4,8) public void dijkstra(int vOrigen) { }
6: 4 6 0 8 5 1 0 1 0 0 1 0 (2,6), (4,8)
2: 4 5 4 6 0 7 16 5 1 1 1 0 0 1 0 (4,7), (4,8), (5,16) } /* Fin de la clase Grafo<E> */
4: 3 5 6 7 4 6 0 7 9 5 11 1 1 1 1 0 1 0 (4,8), (5,9), (7,11), (5,16)
5: 7 4 6 0 7 9 5 11 1 1 1 1 1 1 0 (7,11), (5,16)
2
7: 6 4 6 0 7 9 5 11 1 1 1 1 1 1 1 (5,16) v1 v2
4 10
4 1
Faltara incorporar la informacin de v3
2 8
v4 v5
4 2
los caminos mnimos 5 6
v6 v7
1
21 22

El mtodo dijkstra de CaminosDelGrafo El mtodo dijkstra de CaminosDelGrafo


(1/2) (2/2)
while (!qPrior.esVacia()) { // Mientras haya vrtices por explorar
public void dijkstra(int vOrigen) {
// El siguiente vrtice a explorar es el de menor distancia
distanciaMin = new double[numVertices() + 1]; int v = qPrior.eliminarMin().codigo;
caminoMin = new int[numVertices() + 1]; if (visitados[v] == 0) { // Evitamos repeticiones
visitados = new int[numVertices() + 1]; visitados[v] = 1;
for (int i = 1; i <= numVertices(); i++) { ListaConPI<Adyacente> aux = adyacentesDe(v);
distanciaMin[i] = INFINITO; for (aux.inicio(); !aux.esFin(); aux.siguiente()) {
caminoMin[i] = -1; Adyacente a = aux.recuperar();
} int w = a.destino; double costeW = a.peso;

distanciaMin[vOrigen] = 0; // Vemos si la mejor forma de alcanzar w es a travs de v


if (distanciaMin[w] > distanciaMin[v] + costeW) {
ColaPrioridad<DistanciaHastaV> qPrior = new
MonticuloBinario<DistanciaHastaV>(); distanciaMin[w] = distanciaMin[v] + costeW;
caminoMin[w] = v;
qPrior.insertar(new DistanciaHastaV(vOrigen, 0));
qPrior.insertar(new DistanciaHastaV(w, distanciaMin[w]));
Tdijkstra O(|E| log|E|)
} } } } }
23 24
La Clase DistanciaHastaV Ordenacin Topolgica
package librerias.estructurasDeDatos.grafos; Un Orden Topolgico ordena los vrtices de un grafo
public class DistanciaHastaV implements dirigido acclico de manera que si hay un camino de u a v
Comparable<DistanciaHastaV> { entonces u aparece antes que v en la ordenacin.
protected int codigo; No se puede obtener un orden topolgico en un grafo con
protected int coste; ciclos.
public DistanciaHastaV(int codigo, int coste){
Ejemplo: Obtencin de prerrequisitos de asignaturas.
this.codigo = codigo; so fco
this.coste = coste; Ejemplos de ordenes topolgicos:
<fco,so,so2>
} etc
so2 v4 <prg,bda,dbd>
public int compareTo(DistanciaHastaV eh){ <prg,eda>
if (coste < eh.coste) return -1; prg dbd
else if (coste > eh.coste) return 1; Una Ordenacin Topolgica encuentra
bda
else return 0; todos los ordenes topolgicos sobre un
mda grafo acclico dado.
}} eda
25 26

Estrategia para el Clculo de la Ordenacin


Topolgica Ejemplo de Ordenacin Topolgica
Empleamos un recorrido en profundidad (DFS) pero utilizando Aplicamos la Ordenacin Topolgica al siguiente grafo:
una Pila para almacenar aquellos elementos que ya han sido El mtodo nos devolver una secuencia de vrtices que cumplen
recorridos completamente. una ordenacin topolgica.
El uso de una Pila permite obtener los caminos en el orden Para ello, realizaremos una traza del mtodo de ordenacin
topolgico correcto. topolgica para ver como se va llenando la pila de elementos ya
visitados.
so fco 7
Partimos del vrtice 1 2
etc 6
3
so2 v4
11
prg dbd fco etc mda prg eda bda dbd so so2 8
bda 4

eda
mda 5
5 9
9

27 28
Ejemplo de Ordenacin Topolgica Ejemplo de Ordenacin Topolgica
Vrtice Visitados Pila pVrecorridos
Si representamos la secuencia de vrtices obtenida en lnea y dibujamos las
123456789 aristas, se puede apreciar mejor el orden topolgico.
000000000
1: 2 3 4 5 100000000 <> 7
2
2: {} 120000000 <2>
6
3: 2 6 8 123000000 <2> 3
6: 7 123004000 <2> Grafo Original
1
7: 2 123004500 <7, 2>
8
--- 123004500 <6,7,2> 4
8: 6 123004560 <8,6,7,2>
5 9 Grafo mostrado en orden topolgico
--- 123004560 <3,8,6,7,2>
4: 3 8 123704560 <4,3,8,6,7,2>
5: {} 123784560 <5,4,3,8,6,7,2>
--- 123784560 <1,5,4,3,8,6,7,2>
9 1 5 4 3 8 6 7 2
9: 5 8 123784569 <9,1,5,4,3,8,6,7,2>
29 30

Modificaciones en la clase Grafo para Implementacin de Ordenacin


Ordenacin Topolgica Topolgica (1)
public abstract class Grafo<E> { public int[] toArrayTopologico() {

visitados = new int[numVertices() + 1];
/* Para la ordenacin topolgica */
ordenVisita = 1 ;
protected Pila<Integer> pVRecorridos;
Pila<Integer> pVRecorridos = new ArrayPila<Integer>();
for (int vOrigen = 1; vOrigen <= numVertices(); vOrigen++) {
public int[] toArrayTopologico() { }
if (visitados[vOrigen] == 0)
protected void ordenacionTopologica(int origen, Pila<Integer>
pVRecorridos) { } ordenacionTopologica(vOrigen, pVRecorridos);
}
} int res[] = new int[numVertices() + 1];
for (int i = 1; i <= numVertices(); i++) res[i] = pVRecorridos.desapilar();
return res;
}

31 32
Implementacin de Ordenacin
Topolgica (2) rbol Generador Mnimo: Introduccin
protected void ordenacionTopologica(int origen, Un grafo no dirigido es conexo si cualquier par de vrtices
Pila<Integer> pVRecorridos) { estn conectados por un camino.
visitados[origen] = ordenVisita++; Un rbol es un grafo no dirigido acclico y conexo.
ListaConPI<Adyacente> aux = adyacentesDe(origen); Un rbol generador mnimo (o rbol recubridor mnimo
for (aux.inicio(); !aux.esFin(); aux.siguiente()) { (minimum spanning tree)) de un grafo es un subgrafo que es
int destino = aux.recuperar().destino; un rbol y permite conectar todos los vrtices donde la suma
del peso de sus aristas debe ser lo ms pequea posible.
if (visitados[destino] == 0)
El rbol generador mnimo de un grafo tiene:
ordenacionTopologica(destino, pVRecorridos); El mismo nmero de vrtices
} Un subconjunto de sus aristas
pVRecorridos.apilar(new Integer(origen)); Dos algoritmos de clculo del rbol generador mnimo.
} Algoritmo de Kruskal
Algoritmo de Prim
33 34

rbol Generador Mnimo: Ejemplo Algoritmo de Kruskal


1. Guardar las aristas en una Cola de Prioridad en base a la
Ejemplo de rbol generador mnimo a partir de un grafo.
ponderacin de la arista.
Cableado de una red de datos en un rea metropolitana
2. Partimos de un grafo sin aristas (solo con vrtices).
3
7 8 3
2 7 3. Mientras |E|<|V|-1 hacer:
7 2
3
6 1. Recuperar y eliminar la arista de menor coste de la cola de
2 3
1 3 2 6 prioridad.
9 1 3
9 2. Si no provoca ciclos en el grafo, incluir la arista en el grafo.
1 2
8
1
5 8 2
5
Consideraciones:
4 8
13 4 Ntese que para conectar un grafo con N vrtices son
4 necesarias N-1 aristas.
4
5 9
3 5 9 El resultado final es un rbol (grafo acclico).
3

El rbol generador mnimo permite conectar todos los vrtices con coste Complejidad temporal:
mnimo. Tkruskal(|E|, |V|) = O(|E| * log2(|V|))
35 36
Ejemplo Animado del Algoritmo de
Kruskal Algoritmo de Prim
El algoritmo de Kruskal siempre selecciona la arista de menor
3
7 8 3 peso, causando una construccin desordenada del rbol.
2 7
7 2 El algoritmo de Prim provoca un crecimiento ordenado a
3
2 6 3
1 3 2 6 partir de un determinado vrtice (elegido de forma arbitraria).
9 1 3
1 8
9 Pasos:
2 1
5 8 2
5
1. El rbol resultante (V, E) contiene inicialmente un solo
4 8
13 4 vrtice (arbitrario) y ninguna arista.
4
5 9
4 2. Mientras |V| < |V| hacer
3 5 9 1. Buscar la arista e = (u,v) de coste mnimo, con u V y v no
3
pertenece a V.
Se van eligiendo las aristas de menor de coste y, si no forman 2. E = E + e
ciclos, se aaden al rbol. 3. V = V + v
A igualdad de coste, las aristas se escogen de forma arbitraria. Complejidad temporal: Tprim(|E|, |V|) = O(|E| * log2(|V|))
37 38

Potrebbero piacerti anche