Documentos de Académico
Documentos de Profesional
Documentos de Cultura
EDA-6
Bibliograf a Introduction to Algorithms, de Cormen, Leiserson y Rivest (cap tulos 24, 25 y 26)
FI UPV: Curso 2009/2010 Pgina 6.1 a
EDA-6
a
8
a
2 9 8
b
6 6
4 5
e
1 3
b
6 6
4 5
e
1 3
Pgina 6.2 a
EDA-6
1. ALGORITMO DE KRUSKAL
Idea voraz: construir incrementalmente un bosque (de recubrimiento), seleccionando en cada paso una arista (u, v) A tal que: No se cree ningn ciclo. u Produzca el menor incremento de peso posible. El resultado del algoritmo es un rbol libre (no enraizado) formado por los mismos a vrtices del grafo y un subconjunto de |V | 1 aristas. e
1 2 3 4 5 6 7 8 9 10 11 12 13
GrafoPonderado* Kruskal (GrafoPonderado *G) { // Pseudo-cdigo o // El arbol de recubrimiento tiene los mismos vrtices que G: e GrafoPonderado *MST = new GrafoPonderado(G->vertices); // Cola de prioridad, las aristas se extraen por menor peso: ColaPrioridad Q(G->aristas); arista a; while (MST->NumAristas() < MST->NumVertices()-1 && Q.extraer(a)) { if (a no crea un ciclo en MST) MST->insertarArista(a); } return MST; }
Pgina 6.3 a
EDA-6
1. ALGORITMO DE KRUSKAL
Problema: Cmo vericar ecientemente la condicin de no crear ciclo? o o Solucin: Mantener una coleccin de subconjuntos (disjuntos) con los vrtices o o e de cada rbol del bosque: Una arista (u, v) no crear ciclo si u y v estn en a a a distintos subconjuntos componentes conexas estructurar el conjunto de aristas seleccionadas como un MFset de vrtices. e
Problema: Cmo seleccionar ecientemente la arista de menor peso en cada o iteracin? o Solucin: Manteniendo las aristas en una cola de prioridad (por ejemplo, un o MinHeap) organizadas segn su peso. u
Pgina 6.4 a
EDA-6
1. ALGORITMO DE KRUSKAL
1 2 3 4 5 6 7 8 9 10 11 12 13
GrafoPonderado* Kruskal (GrafoPonderado *G) { // Pseudo-cdigo o GrafoPonderado *MST = new GrafoPonderado(G->vertices); ColaPrioridad Q(G->aristas); mfset m(G->NumVertices()); while (MST->NumAristas() < MST->NumVertices()-1 && Q.extraer((u,v))) { if (m.find(u) != m.find(v)) { m.merge(u,v); MST->insertarArista((u,v)); } } return MST; }
Pgina 6.5 a
EDA-6
1. ALGORITMO DE KRUSKAL
El coste es O(|A| log |A|) construir MFsets de talla |V | O(|V |) construir MinHeap +O(|A|)
En general, el coste es bastante inferior a la cota O(|A| log |A|): Si m es el nmero de iteraciones del bucle while, t u picamente m |V | y si |V | |A| |V |2, en la prctica, el coste est ms cercano a a a a |A| + |V | log |V |
Pgina 6.6 a
EDA-6
a
8 9 4 6 5 2 1 (a,d) 2
(c,e) 1 (c,d) 4
b
6
e
3 (e,d) 3 (c,a) 4 (b,d) 6 (b,e) 5
d
(a,e) 9 (b,c) 6 (b,a) 8
Pgina 6.7 a
EDA-6
a
8 9 4 6 5 2 1
b
6
e
3 (b,c) 6
(c,a) 4
(b,d) 6
(b,e) 5
d
(a,e) 9 (b,a) 8
a
(c,e) 1
c e
Pgina 6.8 a
EDA-6
a
8 9 4 6 5 2 1
b
6
e
3 (b,c) 6
(b,a) 8
(b,d) 6
(b,e) 5
d
(a,e) 9
a
2 1
(a,d) 2
a d
c e
Pgina 6.9 a
EDA-6
a
8 9 4 6 5 2 1
b
6
e
3 (a,e) 9
(b,a) 8
(b,d) 6
(b,e) 5
a
2 1
e
3
(e,d) 3
a d c e
Pgina 6.10 a
EDA-6
a
8 9 4 6 5 2 1
b
6
e
3 (a,e) 9
(b,a) 8
(b,d) 6
a
2 1
e
3
(c,a) 4
a d c e
c
FI UPV: Curso 2009/2010
Pgina 6.11 a
EDA-6
a
8 9 4 6 5 2 1
b
6
e
3 (a,e) 9
(b,a) 8
a
2 1 (c,d) 4
e
3
a d c e
c
FI UPV: Curso 2009/2010
Pgina 6.12 a
EDA-6
a
8 9 4 6 5 2 1
b
6
e
3 (a,e) 9
a b c
FI UPV: Curso 2009/2010
2 1
e
3
(b,e) 5
a d c e b
d
Pgina 6.13 a
EDA-6
2. ALGORITMO DE PRIM
Idea voraz: Empezando por cualquier vrtice, construir incrementalmente un rbol de e a recubrimiento, seleccionando en cada paso una arista (u, v) del grafo tal que: Si se aade (u, v) al conjunto de aristas del rbol de recubrimiento obtenido hasta el n a momento no se cree ningn ciclo. u Produzca el menor incremento de peso posible.
1 2 3 4 5 6 7 8 9 10 11 12
GrafoPonderado* Prim (GrafoPonderado *G) { GrafoPonderado *MST = new Arbol(G->vertices); ConjuntoVertices S; S.insertar(vertice arbitrario de G); int NumVertices = 1; while ( NumVertices != G->vertices ) { arista a= argmin { peso(u,v) | u en S, v en V-S }; S.insertar(v); NumVertices++; MST->insertarArista(a); } return MST; }
Pgina 6.14 a
EDA-6
2. ALGORITMO DE PRIM
Problema: El coste cbico del algoritmo bsico de Prim est dominado por el coste u a a cuadrtico de la operacin de seleccin (argmin), que debe considerar todos los pares de a o o vrtices de S (ya seleccionados) y vrtices del grafo no incluidos en S. e e Solucin: Esta operacin puede implementarse con un coste lineal mediante la idea de o o Prim: Mantener para cada vrtice no seleccionado v V S el identicador e de un vrtice ya seleccionado u S ms prximo a l; es decir, e a o e v V S, P [v] = u = argmin p(x, v)
xS
Estos identicadores se pueden mantener en un vector P . Como en cada iteracin slo se o o aade un nuevo vrtice a S, P puede actualizarse en |V S| = O(|V |) pasos. n e
Pgina 6.15 a
EDA-6
2. ALGORITMO DE PRIM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
GrafoPonderado* Prim (GrafoPonderado *G) { GrafoPonderado *MST = new Arbol(G->vertices); VectVertBool S; VectVertVert P; VectVertFloat D; u = vertice arbitrario de G; for (k = 0; k < G->vertices; k++) { S[k] = false; P[k] = u; D[k] = peso(k,u); } S[u] = true; int NumVertices = 1; while ( NumVertices != G->vertices ) { for (k=0, minp = infinito; k < G->vertices; k++) if (!S[k] && minp > D[k]) { minp=D[k]; v=k; } S[v] = true; NumVertices++; MST->insertarArista((v,P[v])); for (k=0; k < G->vertices; k++) if (!S[k] && D[k] > peso(k,v)) { P[k]=v; D[k]=peso(k,v); } } return MST; }
Pgina 6.16 a
EDA-6
a
8 9 4 6 5 2 1
a
9
b
6
e
3
b c
4 1
e
3
d
P a e b e c e d e e 0
Pgina 6.17 a
EDA-6
a
8 9 4 6 5 2 1
a e
3
b
6
b c
4 5 1
e
3
d
P a c b e c 0 d e e 0
Pgina 6.18 a
EDA-6
a
8 9 4 6 5 2 1
a e
3
b
6
b c
2 5 1
e
3
d
P a d b e c 0 d 0 e 0
Pgina 6.19 a
EDA-6
a
8 9 4 6 5 2 1
a e
3
b
6
b c
2 5 1
e
3
d
P a 0 b e c 0 d 0 e 0
Pgina 6.20 a
EDA-6
a
8 9 4 6 5 2 1
a e
3
b
6
b c
2 5 1
e
3
d
P a 0 b 0 c 0 d 0 e 0
Pgina 6.21 a
EDA-6
2. ALGORITMO DE PRIM
Coste O(|V |2). Si se utiliza un MinHeap para guardar la informacin de los vectores P y D, podemos o obtener el m nimo de D y eliminarlo del conjunto en O(log |V |) Es necesario utilizar un MinHeap doblemente indexado para poder modicar los valores asociados a determinados vrtices. e El nmero de modicaciones en cada paso ser el grado del vrtice que aadimos u a e n al rbol. El coste de cada modicacin es O(log |V |) y el nmero total de a o u modicaciones a lo largo del algoritmo es O(|A|). Esta versin tiene, pues, un coste O(|A| log |V |), que es ventajoso para grafos o dispersos pero no para grafos densos.
Pgina 6.22 a
EDA-6
PRIM O(|V |2) Grafo Denso (|A| |V |2) Grafo Disperso (|A| |V |)
FI UPV: Curso 2009/2010
EDA-6
Dado un grafo G = (V, A) dirigido y ponderado por una funcin o p : A R0, se dene el peso de un camino v0, v1, . . . , vk como la suma de los pesos de sus aristas:
k
u 10 s 5 x 2 3
9 7 2
p(v0, v1, . . . , vk ) =
i=1
p(vi1, vi)
Problema: Se quiere calcular el camino de m nimo peso (camino ms corto) y a su peso asociado desde un vrtice origen s a un vrtice destino t. e e
Pgina 6.24 a
EDA-6
Si el grafo es no dirigido, podemos obtener un grafo dirigido sin ms que a duplicar cada arista {u, v} en cada direccin: (u, v) y (v, u) ambas con el o mismo peso. Por tanto, reducimos el problema al caso de grafos dirigidos. Si no hay una arista entre dos vrtices, podemos asumir que es equivalente e a que exista una arista con peso innito. Es posible que no exista el camino de menor coste entre dos vrtices s y t si e podemos llegar de s a t por un camino que incluya un ciclo de peso negativo. En tal caso, dando sucientes vueltas al ciclo podemos obtener caminos de peso arbitrariamente bajo.
Pgina 6.25 a
EDA-6
Si todos los arcos tienen el mismo peso y ste es positivo, el algoritmo de e bsqueda primero en anchura (BFS, visto en tema 4) desde s nos proporciona u los costes de s a todos los dems vrtices. a e En el caso de grafos ac clicos, podemos utilizar tcnicas de programacin e o dinmica (se ver en la asignatura Algor a a tmica). En el caso de grafos con ciclos y pesos positivos, podemos utilizar el algoritmo de Dijkstra, que veremos a continuacin. o
Pgina 6.26 a
EDA-6
Para grafos con ciclos y pesos negativos, es posible utilizar el algoritmo de Bellman-Ford, que adems puede detectar la presencia de ciclos de peso a negativo en el camino de s a t. Para calcular el coste de todos los caminos entre todos los pares de vrtices e del grafo, podemos iterar con uno de los algoritmos previos o bien utilizar el algoritmo de Floyd-Warshall. Existen otros algoritmos. Por ejemplo, cuando es fcil obtener una cota a optimista ajustada de la distancia (como la distancia eucl dea entre ciudades, etc.) es posible utilizar tcnicas de ramicacin y poda. e o
Pgina 6.27 a
EDA-6
3. ALGORITMO DE BELLMAN-FORD
Queremos calcular la distancia desde s. Mantenemos en un vector D una cota superior D[u] de la distancia de s a u. Utilizamos las aristas para mejorar la cota:
1
Inicializar vector D con D[v]=infinito excepto D[s]=0; Iterar |V|-1 veces: Para cada arista (u,v) del grafo: Si (D[v] > D[u]+coste(u,v)) D[v] = D[u]+coste(u,v); FinPara FinIterar Para cada arista (u,v) del grafo: Si (D[v] > D[u]+coste(u,v)) BUCLE NEGATIVO, PARAR FinPara Devolver D[t]
En el caso general (pesos negativos) es necesario procesar las aristas ms de a una vez.
FI UPV: Curso 2009/2010 Pgina 6.28 a
EDA-6
3. ALGORITMO DE DIJKSTRA
Requiere pesos positivos. Consigue procesar los vrtices y aristas una sola vez. e Utiliza el mismo vector de cotas superiores de la distancia desde s que BellmanFord. La diferencia estriba en que se puede garantizar un orden de seleccin o de vrtices de modo que cada vrtice seleccionado tiene en D la verdadera e e distancia, no slo una cota. o Es decir, este algoritmo mantiene un conjunto de vrtices S cuyo peso del camino e ms corto desde el origen s ya es conocido. El algoritmo va seleccionando el a vrtice u V S con la mejor estimacin del camino m e o nimo, lo inserta en S y utiliza las aristas que salen de u para actualizar la cota de los vrtices de e V S. Idea voraz: empezando en el vrtice origen s, construir incrementalmente e caminos a los dems vrtices seleccionando en cada paso un vrtice v no a e e seleccionado anteriormente tal que: Exista algn vrtice u V ya seleccionado previamente tal que (u, v) A. u e Al aadir (u, v) al camino que terminaba en u se produzca el menor n incremento de peso posible.
Pgina 6.29 a
EDA-6
3. ALGORITMO DE DIJKSTRA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
int Dijkstra(GrafoDirigidoPonderado *G, int s, int t) { vectorVerticeFloat Distancia; vectorVerticeBoolean Fijados; for (int u = 0; u < G->vertices; u++) { Distancia[u] = infinito; Fijados[u] = false; } Distancia[s] = 0; while (not Fijados[t]) { min = infinito; for (int u=0; u < G->vertices; u++) if (!Fijados[u] && Distancia[u] < min) { min=Distancia[u]; v=u; } Fijados[v] = true; for ((v,w) arista de G) if (!Fijados[w] && Distancia[w] > Distancia[v] + peso(v,w)) Distancia[w] = Distancia[v] + peso(v,w); } return Distancia[t]; }
Pgina 6.30 a
EDA-6
9 7 2
y
D[s] 0 D[u] D[v] D[x] D[y]
Pgina 6.31 a
EDA-6
9 7 2
y
D[s] 0 0 D[u] 10 D[v] D[x] 5 D[y]
Pgina 6.32 a
EDA-6
9 7 2a
y
D[s] 0 0 0 D[u] 10 8 D[v] 14 D[x] 5 5 D[y] 7
Pgina 6.33 a
EDA-6
9 7 2a
y
D[s] 0 0 0 0 D[u] 10 8 8 D[v] 14 13 D[x] 5 5 5 D[y] 7 7
Pgina 6.34 a
EDA-6
9 7 2a
y
D[s] 0 0 0 0 0 D[u] 10 8 8 8 D[v] 14 13 9 D[x] 5 5 5 5 D[y] 7 7 7
Pgina 6.35 a
EDA-6
9 7 2a
y
D[s] 0 0 0 0 0 0 D[u] 10 8 8 8 8 D[v] 14 13 9 9 D[x] 5 5 5 5 5 D[y] 7 7 7 7
Pgina 6.36 a
u s x y u v
EDA-6
9 7 2
y
D[s] 0 0 0 0 0 0 D[u] 10 8 8 8 8 D[v] 14 13 9 9 D[x] 5 5 5 5 5 D[y] 7 7 7 7
Pgina 6.37 a
u s x y u v
EDA-6
S
p2 s x p1 s y p1 x y
p2
Esta demostracin requiere que todos los pesos de las aristas sean positivos. Por o tanto, D[u] es la distancia del camino ms corto desde el origen s al vrtice u. a e
FI UPV: Curso 2009/2010 Pgina 6.38 a
EDA-6
G implementado como una lista de adyacencia Existen |V | operaciones de extraccin del m o nimo en el vector, con un coste O(|V |). Cada vrtice v V se ja exactamente una vez, de forma que cada arista en la lista de e adyacencia se examina una unica vez. Debido a que el nmero total de aristas en G es u |A|, existen |A| iteraciones de este bucle, y cada iteracin tiene un coste O(1). o Por tanto, el coste total del algoritmo es O(|V |2 + |A|) = O(|V |2).
Pgina 6.39 a
EDA-6
Pgina 6.40 a
EDA-6
void Dijkstra(GrafoDirigidoPonderado *G, int s, int t, float *Distancia, int *Predecesor) { vectorBoolean Fijados; for (int u = 0; u < G->vertices; u++) { Distancia[u]=infinito; Fijados[u]=false; Predecesor[u]=s; } Distancia[s] = 0; while (not Fijados[t]) { // para calcular dist. Ao nicamente a t min = infinito; for (int u=0; u < G->vertices; u++) if (!Fijados[u] && Distancia[u] < min) { min=Distancia[u]; v=u; } Fijados[v] = true; for ((v,w) arista de G) if (!Fijados[w] && Distancia[w] > Distancia[v] + peso(v,w)) { Distancia[w]=Distancia[v]+peso(v,w); Predecesor[w]=v; } } // devolvemos por ref. Distancia y Predecesor (para recuperar camino) }
Pgina 6.41 a
EDA-6
Pgina 6.42 a
EDA-6
void TodosCaminosCortos (GrafoPonderado *G, MatrizDistancias &M) { for (u = 0; u < G->vertices; u++) M[u] = Dijkstra(G, u); // calcula la distancia // de u a todos los dems a }
Si el coste del algoritmo de Dijsktra es O(|V |2), entonces el coste temporal de este algoritmo es O(|V |3) y el coste espacial es O(|V |2). Para grafos dispersos, se puede obtener una implementacin ms cuidada para el o a algoritmo de Dijsktra de O((|V | + |A|) log |V |), por tanto el algoritmo propuesto ser O(|V |(|V | + |A|) log |V |). a
Pgina 6.43 a
EDA-6
Una red de ujo G = (V, E) es un grafo dirigido en el cual cada arista (u, v) E tiene asociada una capacidad mxima c(u, v) 0. a Si una arista no pertenece a la red de ujo, entonces se supone que su capacidad mxima es 0. a Una red de ujo tiene dos nodos especiales denominados fuente y sumidero. Un ujo en una red de ujo es un conjunto de pesos no negativos de aristas que satisfacen las condiciones: Ningn peso es mayor que la capacidad de la arista u El ujo total que entra en un nodo es igual al ujo total que sale del nodo (excepto para los nodos fuente y sumidero).
Pgina 6.44 a
EDA-6
Sea G = (V, E) una red de ujo con una fuente s y un sumidero t. Un ujo en G es un funcin f : V V R que cumple tres propiedades: o Restriccin de capacidad: u, v V, f (u, v) c(u, v) o Simetr inversa: u, v V, f (u, v) = f (v, u) a Conservacin de ujo: para todo u V {s, t}, o
vV
f (u, v) = 0.
El valor f (u, v) se denomina ujo del nodo u al nodo v. El valor de un ujo f (denotado como |f |) se dene como: |f | = vV f (s, v), es decir, el ujo total que sale de la fuente. Dada una red de ujo G con una fuente s y un sumidero t, el problema del ujo mximo consiste en encontrar un ujo de valor mximo. a a
Pgina 6.45 a
EDA-6
El problema del ujo mximo no slo es importante desde un punto de a o vista terico, sino que tiene aplicaciones prcticas en multitud de problemas o a de planicacin, asignacin de recursos, sirve de modelo para una variedad de o o problemas de programacin lineal, acoplamiento en grafos bipartidos, problemas o de conectividad, etc. Este problema est estrechamente relacionado con encontrar la cortadura a m nima entre s y t en el grafo.
Pgina 6.46 a
EDA-6
c(u, v)
El ujo de s a t en G puede calcularse considerando unicamente las aristas que van de un vrtice de X a otro de Y . e Consecuentemente, para cualquier ujo f y cualquier cortadura (X, Y ) se cumple |f | cap(X, Y ). El teorema ujo mximo cortadura m a nima establece que esa desigualdad se alcanza para el ujo mximo. Es decir, f es un ujo mximo si y slo a a o si |f | = cap(X, Y ) para una cortadura (X, Y ) del grafo, y en tal caso esa cortadura tiene capacidad m nima.
FI UPV: Curso 2009/2010 Pgina 6.47 a
EDA-6
Los algoritmos para encontrar el ujo mximo pueden dividirse en dos familias a en funcin de si mantienen o no la restriccin de conservacin de ujo: o o o Caminos de aumento Se basan en mantener un ujo vlido en todo momento. a Aumentan el ujo de s a t de manera iterativa. Partiendo de un ujo posible arbitrario (por ejemplo, ujo nulo) se busca un camino de s a t en un grafo residual que permita aumentar el ujo. Bajo ciertas condiciones se garantiza la terminacin del algoritmo. o Enviar preujo Se relajan las condiciones a cumplir durante el transcurso del algoritmo. Concretamente, se permite que el ujo neto en los vrtices pueda e ser positivo, si bien al nalizar el algoritmo el ujo debe cumplir la condicin o de conservacin de ujo. Se basan en enviar el exceso de ujo hacia el o sumidero asociando a cada vrtice una altura para controlar la direccin e o de env del exceso de ujo. o
FI UPV: Curso 2009/2010 Pgina 6.48 a
EDA-6
Pgina 6.49 a
EDA-6
inicializar flujo f=0; construir grafo residual Gf asociado a f=0; maxflow = 0; while (existe camino de aumento de s a t en Gf) { delta = menor capacidad del camino de aumento; maxflow += delta; para cada arista (u,v) del camino de aumento hacer { c_f(u,v) -= delta; c_f(v,u) += delta; } } return maxflow;
Pgina 6.50 a
EDA-6
Pgina 6.51 a
EDA-6
Pgina 6.52 a