Capı́tulo VII Árboles y Grafos VII.1. Árboles Binarios VII.1.1. Definiciones Definición. Un árbol binario T es una estructura tal que: T es vacı́o, ó T consiste de un nodo, llamado la raı́z de T , y dos árboles binarios llamados el subárbol izquierdo y el subárbol derecho de T . cada uno de los cuales es un arbol binario. Decimos que un nodo v está en un árbol T si v es la raı́z ó v está (recursivamente) en uno de los subárboles de T . Un nodo en un árbol se llama terminal u hoja, si sus subárboles son vacı́os. Un nodo que no es terminal se llama interno. Ejemplo. Un árbol se ilustra como se muestra en la figura. La raı́z es a y se une con dos “arcos” a las raı́ces de sus subárboles. Procediendo recursivamente se dibuja todo el árbol. Los nodos d, g, j, k, i son terminales, y los otros son internos. a c b e d f g h j i k 1 2 CAPÍTULO VII. ÁRBOLES Y GRAFOS Definición. En un árbol binario no vacı́o T , el nivel ó profundidad de un nodo v en T se define como 0, si v es la raı́z de T , 1 más el nivel de v en el subárbol de T que contiene v, si v no es la raı́z de T El k-ésimo nivel de un árbol T es el conjunto de nodos con nivel k en T . El nivel de un nodo es también el número de arcos en el “camino” desde el nodo hasta la raı́z. Definición. La altura de un árbol binario no vacı́o T es 0 si T tiene ambos subárboles vacı́os, y es el máximo de las alturas de sus subárboles no vacı́os más 1, en caso contrario. La altura de un árbol binario T es también el máximo nivel de cualquier nodo en el árbol. Por ejemplo, en el árbol de la figura arriba, el nivel de a (en el árbol completo) es 0, el nivel de e es 2, y el nivel de k es 4. La altura de ese árbol es 4. Proposición. Para todo n ≥ 1, cualquier árbol binario de altura h tiene a lo mas 2h terminales. La prueba es por inducción sobre la altura usando la definición recursiva de árbol y de altura. Esto implica la siguiente proposición. Proposición. Sea T un árbol binario con n terminales. Entonces la altura de T es al menos dlog2 ne. VII.1.2. Ejemplo: Árbol de Ordenamiento Definición. Un árbol de ordenamiento para una lista L[0 : n − 1] de ı́tems diferentes es un árbol binario tal que cada nodo interno v tiene asociada una comparación “ L[i] : L[j]”; el subárbol izquierdo de v corresponde al resultado L[i] < L[j], y el subárbol derecho de v corresponde al resultado L[i] > L[j] de la comparación. cada terminal w tiene asociado un ordenamiento L[i0 ] < L[i1 ] < L[i2 ] < · · · < L[in−1 ] el cual es el único consistente con los resultados de la comparaciones realizadas en los ancestros de w VII.1. ÁRBOLES BINARIOS 3 a:b b:c a<b<c a:c a:c a<c<b b<a<c c<a<b b:c b<c<a c<b<a Ejemplo. El siguiente árbol corresponde a ordenamiento por inserción con 3 elementos a, b, c: Es posible que no exista un ordenamiento consistente con uno de los resultados de una comparación y las anteriores comparaciones. En ese caso esa ramificación se elimina. Por ejemplo, en la comparación a : c en la parte izquierda es redundante, a:b b:c a:c a<b<c a:c a:c a<c<b b<a<c c<a<b b:c b<c<a c<b<a y no es posible que como resultado se tenga a > c (por lo tanto no se tiene el subárbol correspondiente). Teniendo esto en cuenta, el número de terminales del árbol de ordenamiento debe ser exactamente n!. Proposición. Cualquier árbol de ordenamiento para n ı́tems diferentes tiene una altura al menos dlog2 (n!)e. Prueba. Por la proposición anterior puesto que el número de nodos terminales es n!. Proposición. Calquier algoritmo basado en comparaciones, para ordenar n ı́tems diferentes requiere en el peor de los casos al menos (n/2) log2 (n/2) comparaciones. Prueba. Correspondiente a un algoritmo A para ordenar podemos construir un árbol T de ordenamiento. La primera comparación que realiza el algoritmo corresponde a la comparación en la raı́z. El subárbol izquierdo corresponde a la continuación del algoritmo en el caso que L[i] < L[j], y el subárbol derecho corresponde a la continuación del algoritmo en el caso que L[i] > L[j]. Por la proposición anterior, T tiene una altura de al menos dlog2 (n!)e. Esto significa que T tiene una hoja con nivel al menos dlog2 (n!)e. Esto significa que el ordenamiento correspondiente a esa hoja requiere al menos dlog2 (n!)e comparaciones. 4 CAPÍTULO VII. ÁRBOLES Y GRAFOS Finalmente, tenemos la cota: log2 (n!) = = log2 1 + log2 2 + log2 3 + · · · + log2 n ≥ log2 dn/2e + log2 (dn/2e + 1) + · · · + log2 n ignorando términos ≥ log2 dn/2e + log2 dn/2e + · · · + log2 dn/2e todos los términos son mayores que el primero = (n − dn/2e + 1) · log2 dn/2e el # de términos es n − dn/2e + 1 = (bn/2c + 1) · log2 dn/2e ≥ (n/2) log2 (n/2). VII.1.3. Una mejor acotación de log2 (n!). Esto sólo por información a quien quiera ver como integración puede ser útil (no visto en clase). Proposición. n log2 (n/e) + log2 e ≤ log2 (n!) ≤ (n + 1) log2 ((n + 1)/e) + 2 log2 (e/2). Prueba. Acotamos ln(n!). Se tiene que ln(n!) = n X ln k. k=1 Usamos integrales para acotar esta suma como (ver la figura) 1 2 3 4 5 6 n−1 n n+1 Zn ln xdx ≤ 1 Usando que 1 n X k=1 2 3 4 5 6 n−1 n Z n+1 ln k ≤ ln xdx. 2 Z ln xdx = x ln x − x + C se tiene entonces n ln n − n + 1 ≤ ln(n!) ≤ (n + 1) ln(n + 1) − (n + 1) − 2 ln 2 + 2 y por lo tanto n ln(n/e) + 1 ≤ ln(n!) ≤ (n + 1) ln((n + 1)/e) + 2 ln(e/2). Recordando que log2 X = ln X · log2 e tenemos que n log2 (n/e) + log2 e ≤ log2 (n!) ≤ (n + 1) log2 ((n + 1)/e) + 2 log2 (e/2). VII.2. CÓDIGOS DE HUFFMAN VII.2. 5 Códigos de Huffman En computación y comunicaciones digitales se usan representaciones para los diferetes sı́mbolos como secuencias de 0’s y 1’s. Por ejemplo el estándar ASCII representa los carácteres alfanuméricos y otros especiales como secuencias ó cadenas de 8 bits. En comunicaciones es relevante tener representaciones ó códigos con longitudes variables de tal manera que caracteres más frecuentes tengan códigos más cortos que caracteres menos frecuentes. Por ejemplo, tenemos la siguiente tabla de carácteres, frecuencias y códigos (en los ejemplos aquı́, la “frecuencia” va a ser un entero que se entiende como un conteo; podrı́a ser también un real entre 0 y 1 obtenido dividiendo por el conteo total): carácter frecuencia código a 45 0 b 13 101 c 12 100 d 16 111 e 9 1101 f 5 1100 Por ejemplo, si el mensaje es accafeeb entonces su “codificación” correspondiente es 0 100 100 0 1100 1101 1101 101 El receptor del mensaje entonces debe “decodificarlo”. Un código con longitudes fijas no presenta problema porque se toman grupos consecutivos de esa longitud fija y se usa la tabla de códigos en forma inversa. Códigos de longitud variable necesitarı́an una forma de indicar donde comienza y termina un código lo cual requerirı́a el uso de más bits. Una solución son códigos libres de prefijos, en que ningún código es prefijo de otro. La codificación del ejemplo arriba es libre de prefijo. La decodicicación es entonces fácil: se escanea el mensaje hasta que se encuentra el primer código, en lo que no hay ambigüedad, entonces el segundo, y ası́ consecutivamente. Un árbol binario se puede usar para obtener códigos de longitud variable y libres de prefijo. Por ejemplo, el código de la tabla arriba se obtuvo del siguiente árbol binario: Los carácteres se asignan a los nodos terminales 1 1 1 0 0 a 0 1 d 1 b e 0 0 c f y ramificaciones a la izquierda y derecha se hacen corresponder a 1 y 0 respectivamente. Entonces el código de un carácter c está dado por la cadena de 0’s y 6 CAPÍTULO VII. ÁRBOLES Y GRAFOS 1’s que corresponde a las ramificaciones que se siguen cuando se recorre el árbol desde la raı́z hasta el nodo terminal correspondiente a c. Claramente los códigos obtenidos de esta manera son libres de prefijo. Para una código que asigna código(c) al carácter c, el valor del código que se busca minimizar es X valor(código, C, f) = longitud(código(c)) · f(c) c∈C Si el código proviene de un árbol binario como se ha descrito antes entonces (para simplicar, identificamos un carácter con su terminal correspondiente): X valor(T, C, f) = nivel(c, T ) · f(c) c∈C Se busca entonces minimizar este valor sobre todos los árboles binarios posibles. A continuación discutimos un algoritmo para resolver este problema. VII.2.1. Algoritmo de Huffman El algoritmo de Huffman encuentra un árbol óptimo para un conjunto de caracteres C y frecuencias f de la siguiente manera: 1. Determina dos caracteres x y y con mı́nimas frecuencias (no son necesariamente únicos porque varios elementos pueden tener la mı́nima frecuencia, ó la segunda mı́nima). Estos x y y van a ser hermanos en un árbol óptimo. 2. Se reemplazan x y y en C con un carácter nuevo z que tiene frecuencia f(z) = f(x) + f(y), y se encuentra recursivamente un árbol óptimo T 0 para C, f modificados. 3. Un árbol óptimo para C, f original se obtiene reemplazando el nodo terminal de z con un nodo con dos hijos correspondientes a x y y. Aunque descrito recursivamente es fácil de implementar más bien en forma iterativa. VII.2.2. Ejemplo Usamos el ejemplo C, f arriba para mostrar la ejecución del algoritmo: cada columna de la siguiente tabla muestra caracteres y frecuencias (por ejemplo en la primera iteración e y f se convierten en un caracter que escribimos como ef con frecuencia 14, y ası́ sucesivamente): car frec car frec car frec car frec car frec car frec a 45 a 45 a 45 a 45 a 45 a((bc)(d(ef))) 110 b 13 b 13 bc 25 bc 25 (bc)(d(ef)) 55 c 12 c 12 d 16 d 16 d 16 d(ef) 30 e 9 ef 14 ef 14 f 5 VII.2. CÓDIGOS DE HUFFMAN 7 (Es más fácil en el tablero mostrar esto con una ilustración, pero más fácil aquı́ dar la tabla.) El árbol correspondiente se muestra en la figura. No es el mismo que se dió antes, pero los códigos tienen las mismas longitudes y al valor es óptimo. 0 1 0 1 a 1 1 b 0 0 d 1 0 c e VII.2.3. f Pseudocódigo (No se escribió en clase.) Asumimos un tipo de estructura de datos nodo, tal que si z es un nodo, entonces tiene información asociada z.izq y z.der que “apuntan” a los hijos izquierdo y derechos. Con esto tenemos la siguiente versión iterativa del algoritmo de Huffman: Huffman (C, f) 1. n ← |C| B (el tamaño de C) 2. Q ← conjunto de nodos, uno por cada c ∈ C 3. para i ← 1 a n − 1 4. crear nuevo nodo z 5. sean x y y de minimas frecuencias en Q 6. Q ← Q − {x, y} 7. z.izq ← x 8. z.der ← y 9. f(z) ← f(x) + f(y) 10. Q ← Q ∪ {z} 11. devolver el unico elemento que queda en Q Note que al final el único elemento que queda en Q es la raı́z del árbol construı́do. VII.2.4. Justificación La justificación de que el algoritmo de Huffman construye un árbol óptimo se basa en las siguientes observaciones. Se dan un conjunto de carácteres C y sus frecuencias f. Observación. Si x y y son dos caracteres de frecuencias mı́nimas, entonces existe un árbol óptimo que los tiene como hermanos (en nodos terminales) 8 CAPÍTULO VII. ÁRBOLES Y GRAFOS T T’ x y a a b y x b Figura VII.1: En T se intercambian x y a. El árbol y las otras asignaciones de caracteres a terminales no cambia. El valor de estos árboles es igual. Si igualmente se intercambian y y b, se obtiene un árbol óptimo con x y y como hermanos (en nodos terminales). Sea T un árbol de óptimo valor para C, f. Sean a y b dos nodos terminales en T de mayor nivel (profundidad). Si estos son x y y no hay nada que probar. Si no, supongamos que x no es ni a ni b (ver figura). Entonces si se intercambian x y a se obtiene otro árbol (y código) T 0 . Pero puesto que nivel(x, T ) ≤ nivel(a, T ) (por la selección de a y b), y f(x) ≤ f(a) (por la selección de x y y), se tiene que valor(T, C, f) − valor(T 0 , C, f) = = (nivel(x, T )f(x) + nivel(a, T )f(a)) − (nivel(x, T 0 )f(x) + nivel(a, T 0 )f(a)) = (nivel(x, T )f(x) + nivel(a, T )f(a)) − (nivel(a, T )f(x) + nivel(x, T )f(a)) = nivel(a, T )(f(a) − f(x)) − nivel(x, T )(f(a) − f(x)) = (nivel(a, T ) − nivel(x, T )(f(a) − f(x)) ≥ 0 porque ambos factores del producto son ≥ 0. Por otra parte valor(T, C, f) ≤ valor(T 0 , C, f) porque T es óptimo. Por lo tanto valor(T, C, f) = valor(T 0 , C, f), y ası́ T 0 es también óptimo. Si b no es y entonces estos también se pueden intercambiar para obtener de la misma manera un árbol óptimo donde x y y son hermanos. Observación. Sean x y y son dos caracteres de frecuencias mı́nimas en C, f; reemplazamos x y y con un caracter z que tiene frecuencia f(z) = f(x) + f(y) (los otros caracteres y frecuencias no cambian); sean C 0 , f 0 el conjunto de caracteres y frecuencias resultantes. Entonces, si T 0 es un árbol óptimo para C 0 , f 0 entonces T es óptimo para C, f donde T es obtenido como se muestra en la figura: al nodo de z se le agregan hijos que corresponden a los caracteres x y y. Esto no es difı́cil de ver y se deja como ejercicio. VII.3. GRAFOS: CAMINOS MÁS CORTOS 9 T T’ z z x y Figura VII.2: Se encuentra un árbol T 0 óptimo para C 0 , f 0 . Si en T 0 se agregan al nodo terminal de z dos hijos terminales y se asignan a x y y, entonces el árbol T ası́ obtenido es óptimo para C, f. VII.3. Grafos: Caminos Más Cortos VII.3.1. Grafos Definición. Un grafo G consiste de un conjunto de nodos ó vértices V(G) y un conjunto de arcos ó aristas E(G) ⊆ {{u, v} : u, v ∈ V(G), u 6= v}. Si {u, v} ∈ E(G), entonces se dice que u y v son adyacentes en G. (Aquı́ no permitimos múltiples arcos entre nodos, ni arcos entre un nodo y si mismo; además los arcos no tienen dirección. En un contexto más general donde esos casos son permitidos, los grafos que estamos considerando son llamados grafos simples y no dirigidos.) Definición. Un camino en un grafo G es una secuencia de nodos y arcos v0 , e1 , v1 , e2 , v2 , . . . , vk−1 , ek , vk tal que los ei = {vi , vi+1 } son arcos diferentes en E(G). Si los vértices son también diferentes, el camino de dice simple. Ver ejemplos adelante. Para los grafos que consideramos, para un camino es suficiente especificar su secuencia de vértices (la secuencia de arsitas está entonces implı́cita). Los grafos se usan para modelar muy diferentes relaciones (tanto de la vida diaria, como matemáticas). Algunos ejemplos: (1) los nodos son personas y los arcos corresponden a la relación de dos personas conocerse mutuamente; (2) los nodos son ciudades y los arcos corresponden a la existencia de una carretera entre dos ciudades; (3) los nodos son conjuntos y los arcos corresponden a una intersección no vacı́a entre un par de conjuntos; etc. En Johnsonbaugh se pueden encontrar muchos ejemplos. 10 CAPÍTULO VII. ÁRBOLES Y GRAFOS VII.3.2. Problema: Los Caminos Más Cortos Consideramos el siguiente problema motivado por ejemplo con el caso mencionado antes de un grafo donde los nodos son ciudades y los arcos corresponden a conexiones con carretera. Cada una de estas tiene una longitud y uno está interesado en determinar una ruta para llegar de una ciudad a otra pasando posiblemente por otras ciudades, de tal manera que la distancia total recorrida es minimizada. Formalmente, se tiene un grafo G con nodos V(G) y arcos E(G), y una función d : E(G) → R≥0 (reales no negativos) definida sobre los arcos (las longitudes de los arcos), y se especifica un s ∈ V(G); se quiere determinar los caminos lo más cortos (de mı́nima longitud), y sus distancias (longitudes) totales desde s a cada uno de los otros nodos u. La longitud de un camino s = v0 , v1 , v2 , . . . , vk = u es k−1 X d({vi , vi+1 }). i=0 Por supuesto que una forma de resolver este problema es listar los diferentes caminos y sus longitudes y entre estos escoger los más cortos. Pero es posible hacerlo en forma “más eficiente,” es decir, de tal manera que la ejecución en un computador sea más rápida. (Estamos interesados en caminos simples, pero no necesitamos preocuparnos de esto porque repetir vértices no puede acortar distancias, y el algoritmo que vamos a ver elimina automáticamente la posibilidad de repeticiones.) VII.3.3. Algoritmo de Dijkstra La idea del algoritmo es comenzar en el nodo s, el cual es el nodo más cercano a si mismo, e iterativamente determinar el siguiente nodo más cercano a s. Para esto el algoritmo mantiene para cada nodo un valor D[u] el cual es la longitud del mejor camino encontrado hasta el momento (inicialmente D[u] = ∞ para todo u 6= s, ya que inicialmente no se conoce ningún camino). El algoritmo también mantiene para cada nodo u un “apuntador” π[u] al nodo anterior en el camino más corto de s a u encontrado hasta el momento (el camino cuya longitud es D[u]). Correspondientemente, π[u] es “nulo” (ó indefinido) inicialmente. Pseudocódigo El pseudocódigo del algoritmo, llamado el algoritmo de Dijkstra, es el siguiente: VII.3. GRAFOS: CAMINOS MÁS CORTOS 11 Dijkstra (G, d) 1. para v ∈ V(G) 2. D[v] ← ∞ 3. π[v] ← nulo 4. D[s] ← 0 5. Q ← V(G) 6. mientras Q 6= ∅ 7. sea u ∈ Q tal que D[u] es minimo 8. Q ← Q − {u} 9. para v ∈ Ady[u] ∩ Q 10. si D[u] + d({u, v}) < D(v) 11. D[v] ← D[u] + d({u, v}) B el camino a traves de u es mejor 12. π[v] ← u 13. devolver (D, π) Aquı́ Ady[u] = {v ∈ V(G) : {u, v} ∈ E(G)}, el conjunto de nodos adyacentes a u. Al final, D[u] es igual a la distancia más corta de s a u, y π[u] es igual al nodo anterior a u en un camino más corto de s a u. El camino más corto hasta u se puede reconstruir como u, π[u], π[π[u]], π[π[π[u]]], . . .. Ejemplo La siguiente figura muestra en la primera imagen un grafo con nodos a, b, c, . . . , j, y arcos y sus longitudes como aparecen allı́. Las 11 imágenes siguientes muestran los valores D[u], π[u] en los nodos (excepto los valores que son ∞ y nulo) antes del mientras y al finalizar cada una de las iteraciones de este. Los nodos del grafo oscurecidos (en azul) son los que han dejado de estar en Q (y entonces están en S) y los arcos entre ellos son los definidos por los valores π[u]. VII.3.4. Justificación (No se hizo en clase.) Para el análisis general, sea δ(u) la distancia más corta de s a u sobre todos los caminos de s a u en G. Una observación importante en verificar que el algoritmo funciona correctamente es la siguiente: (∗) Si s = v0 , v1 , v2 , . . . , v`−1 , v` , v`+1 , . . . , vk−1 , vk = u es un camino lo más corto de s a u en G entonces la parte inicial de ese camino hasta v` (donde v` puede ser cualquiera de los nodos en ese camino) s = v0 , v1 , v2 , . . . , v`−1 , v` es un camino lo más corto hasta v` . 12 CAPÍTULO VII. ÁRBOLES Y GRAFOS 5 5 5,a c 3 4,a 1 6,b h 5 5,a c g 4 9 ,c 4a 1 2 d 4,a 4 8,h 1 g 1 3 5,a c 5 4 j g 3 1 6 4 9,e 1 i 5 j 5,a c 3 1 e 2 5,d 3 4 5 7,d 9,e 12,f 6 1 j h i 5,a c 5 j 4 2 d 4,a 4 8,h 1 g 5,a c 4 9,c 1 g h 5 5,a c 3 1 e 2 5,d 3 4 5 7,d 9.e 10,i 6 1 j h i j b 3,a 3 3 1 e 5,d 4 7,d 6 6 9,b f 2 5 1 i 3 j b 3,a 6 3 7,e f 1 e 2 5,d 3 4 7,d 9,e 6 1 h i 5 5,a c 5 1 4 3 0 a 7,e f f 2 d 4,a 4 8,h 1 g 6 2 i 4 b 3,a 3 6 0 a 6 e 4 h 2 d 4,a b 3,a 1 e 2 5,d 3 4 5 7,d 9,e 12,f 6 1 j h i 5 7,e f 2 3 3 1 5 9,b f 1 i 1 3 g 6 3 d 4 6 7,e f 0 a 4,a 0 a 2 d 4,a b 3,a j 2 b 3,a 1 e 5,d 4 4 4 9,c 1 g 6 1 3 7,d 6 5 7,e f 3 h f 3,a b 3 4 5,a c 5 i 4 0 a 2 e 3 2 d 4,a 2 5 4 6 h 5 9,b f b 3,a 5,d 4 2 3 3 7,d 6 h 5 e i 1 d 0 a 5,a c 6 4 2 1 g e 3 0 a 4 3 0 a j 6 3 1 d 4 6 3 3 4 1 2 c 0 a b 4 b 3,a 1 d f 5 i 4 2 2 3 a 5 4 6 h 0 a g e 3 1 6 3 1 d 4 g b 4 2 c 0 3 a b 3,a 4 2 d 4,a 4 8,h 1 g 6 3 1 3 7,d 6 h 5 12,f j 5,d e 2 7,e f 4 5 10,i 9,e 1 j i Figura VII.3: Grafo G con longitudes de sus arcos, y antes de la primera y después de cada una de las iteraciones del algoritmo de Dijkstra, con nodo a como s. VII.3. GRAFOS: CAMINOS MÁS CORTOS 13 Esto es fácil de ver: si hubiera otro camino más corto a v` , ese nos darı́a también un camino más corto a u, lo que es una contradicción. Para el propósito de este análisis, sea δ(u) igual la distancia del camino más corto de s a u y sea S = V(G) − Q, el conjunto de nodos ya removidos de Q. Invariante: En cada iteración del mientras, el algoritmo mantiene que (i) cuando un nuevo nodo u es removido de Q (y entonces pasa a S), se tiene que δ(u) = D[u], es decir, el estimativo D[u] es igual a la distancia más corta (ii) para los nodos v que están en Q se mantiene que D[v] es la distancia más corta sobre caminos con nodos en S, excepto v (el cual está en Q). De aquı́ que siempre δ(v) ≤ D[v] para todo v en Q (porque D[v] es la mejor distancia sobre un subconjunto de los caminos, mientras que δ(v) es la distancia sobre todos los caminos). Justificación lı́neas 1-5: Inicialmente sólo la distancia al nodo s ha sido identificada y es 0 (D[s] = 0, las otras se inicializan a ∞ (un número más grande que cualquier otro), y los apuntadores π son inicialmente nulos. Justificación de lı́neas 7-8: Veamos que para el nodo u ∈ Q con D[u] que es mı́nimo, su valor D[u] es la distancia más corta a s. Se sabe ya porque lo garantiza el invariante en la iteración previa que D[u] es la mı́nima distancia sobre caminos C en S (excepto u). Ası́ que consideremos un camino C 0 de s a u que no está completamente en S. Sea y el primer nodo no en S y x el anterior nodo el cual entonces C u s S C’ x y 14 CAPÍTULO VII. ÁRBOLES Y GRAFOS está en S (ver figura). Por la observación (∗) arriba, el segmento de C 0 hasta y es también de mı́nima distancia. Entonces D[y] ≤ = = ≤ D[x] + d({x, y}) por la parte (ii) del invariante arriba para y δ(x) + d({x, y}) por la parte (i) del invariante arriba para x δ(y) porque son longitudes medidas en C 0 δ(u) porque δ(u) es la longitud de todo el camino C 0 y la longitud de C 0 hasta y es menor ó igual que eso ≤ D[u] porque δ(u) ≤ D[u] para todo nodo u De aquı́ que D[y] ≤ D[u]. Pero D[u] ≤ D[y] por que D[u] se ha escogido en la lı́nea 7 como mı́nimo sobre nodos en Q. Por lo tanto D[u] = D[y]. Y entonces D[u] = δ(u) (porque está entre y y u en la cadena de desigualdades arriba). Ası́ que D[u] si es la distancia más corta sobre todos los caminos de s a u. Justificación de lı́neas 9-12: De la iteración anterior se conoce ya la distancia más corta a v ∈ Q usando sólo vértices en S. Pero en esta iteración, se está agregando u a S, por lo tanto se debe examinar si ir a u primero y luego a v (usando el arco {u, v}) es más corto. Esto se debe hacer para todo v ∈ Ady[u] ∩ Q. v x u s S