Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Programacin III
o
Facultad de Informtica - UNLP
a
Alejandro Santos
ale@ralo.com.ar
Curso 2013
(actualizado 29 de julio de 2013)
Prog. III
Indice general
1. Tiempo de Ejecucin
o
1.1. Tiempo de Ejecucin . . . . . . . . . . . . . . . .
o
1.2. Anlisis Asinttico BigOh . . . . . . . . . . . . .
a
o
1.2.1. Por denicin . . . . . . . . . . . . . . . .
o
1.2.2. Ejemplo 1, por denicin Big-Oh . . . . .
o
1.2.3. Por regla de los polinomios . . . . . . . . .
1.2.4. Por regla de la suma . . . . . . . . . . . .
1.2.5. Otras reglas . . . . . . . . . . . . . . . . .
1.2.6. Ejemplo 2, por denicin Big-Oh . . . . .
o
1.2.7. Ejemplo 3, por denicin Big-Oh en partes
o
1.2.8. Ejemplo 4, por denicin. . . . . . . . . .
o
1.3. Anlisis de Algoritmos y Recurrencias . . . . . . .
a
1.3.1. Expresin constante . . . . . . . . . . . .
o
1.3.2. Grupo de constantes . . . . . . . . . . . .
1.3.3. Secuencias . . . . . . . . . . . . . . . . . .
1.3.4. Condicionales . . . . . . . . . . . . . . . .
1.3.5. for y while . . . . . . . . . . . . . . . . . .
1.3.6. for y while, ejemplo . . . . . . . . . . . . .
1.3.7. Llamadas recursivas . . . . . . . . . . . .
1.3.8. Ejemplo 5, iterativo . . . . . . . . . . . . .
1.3.9. Ejemplo 6, recursivo . . . . . . . . . . . .
1.3.10. Ejemplo 7, recursivo . . . . . . . . . . . .
1.3.11. Ejemplo 8, Ejercicio 12.4 . . . . . . . . . .
1.4. Otros ejemplos . . . . . . . . . . . . . . . . . . .
1.4.1. Ejemplo 9 . . . . . . . . . . . . . . . . . .
Planteo de la recurrencia . . . . . . . . . .
Demostracin del orden O(f (n)) . . . . .
o
1.4.2. Ejemplo 10 . . . . . . . . . . . . . . . . .
Antes de empezar . . . . . . . . . . . . . .
Ejercicio . . . . . . . . . . . . . . . . . . .
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
7
8
8
9
9
10
10
11
11
12
13
15
15
15
15
15
15
15
17
17
18
19
21
23
23
23
25
26
26
27
INDICE GENERAL
Prog. III
.
.
.
.
.
.
.
.
.
.
.
.
.
.
31
32
32
33
34
34
35
35
o
3.1.1. Explicacin del problema . . . . . . . . . . . .
o
3.1.2. Implementacin Java . . . . . . . . . . . . . .
o
3.2. M
nimo del Nivel . . . . . . . . . . . . . . . . . . . .
3.2.1. Explicacin del problema . . . . . . . . . . . .
o
3.2.2. Implementacin Java - Recursivo con Integer
o
3.2.3. Implementacin Java - Recursivo con int . . .
o
3.2.4. Implementacin Java - Iterativo . . . . . . . .
o
3.3. Trayectoria Pesada . . . . . . . . . . . . . . . . . . .
3.3.1. Forma de encarar el ejercicio . . . . . . . . . .
3.3.2. Recorrido del arbol . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
39
40
40
40
41
41
42
42
43
44
44
44
44
45
46
46
47
48
48
49
53
53
53
.
.
.
.
57
58
58
58
59
4. Arboles AVL
4.1. Perros y Perros y Gatos . . . .
4.1.1. Explicacin del problema
o
4.1.2. Implementacin Java . .
o
4.2. Pepe y Alicia . . . . . . . . . .
4
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
INDICE GENERAL
Prog. III
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
63
64
67
68
68
68
70
72
72
73
75
75
75
75
76
78
78
78
79
79
80
83
83
83
INDICE GENERAL
Prog. III
Introduccin
o
El presente apunte es una recopilacin de explicaciones y exmenes paro
a
ciales dados como parte de los cursos 2012-2013 de Programacin III de
o
1
Ingenier en Computacin, UNLP . Actualmente se encuentra en estado de
a
o
borrador, y puede contener rro re s u omisiones, por lo que se recomienda
consultar a los docentes ante cualquier duda o ambiguedad.
Puede contactarse con el autor por e-mail a: ale@ralo.com.ar.
http://www.info.unlp.edu.ar/
INDICE GENERAL
Prog. III
Cap
tulo 1
Tiempo de Ejecucin
o
1.1. TIEMPO DE EJECUCION
1.1.
Prog. III
Tiempo de Ejecucin
o
1.2.
CAP
ITULO 1. TIEMPO DE EJECUCION
1.2.1.
Prog. III
Por denicin
o
1.2.2.
(1.2.1)
(1.2.2)
(1.2.3)
(1.2.4)
(1.2.5)
c, n n0
(1.2.6)
11
Prog. III
3
2
(1.2.7)
toma el valor innito. Por ejemplo: para cualquier constante c ja, para
algunos valores de n se cumple, pero para otros no. Con c = 100,
3
2
100, n n0
(1.2.8)
Despejando el valor de n,
n
3
2
log 3
2
3
2
log 3 100, n n0
(1.2.9)
(1.2.10)
n 11,35, n n0
log 3
(1.2.11)
n
2
1.2.3.
1.2.4.
(1.2.12)
CAP
ITULO 1. TIEMPO DE EJECUCION
1.2.5.
Prog. III
Otras reglas
1.2.6.
(1.2.13)
(1.2.14)
(1.2.15)
(1.2.16)
Prog. III
1.2.7.
(1.2.17)
(1.2.18)
(1.2.19)
(1.2.20)
(1.2.21)
(1.2.22)
(1.2.23)
(1.2.24)
(1.2.25)
CAP
ITULO 1. TIEMPO DE EJECUCION
Prog. III
k2 , 2n2 k2 n3 , n n2
2n2
2
k2 k2
3
n
n
(1.2.26)
k3 , n log(n) k3 n3 , n n3
n log(n)
log(n)
k3
k3
3
n
n2
(1.2.28)
(1.2.27)
(1.2.29)
1.2.8.
(1.2.30)
(1.2.31)
(1.2.32)
Prog. III
b) Es de orden O(log4 (n))? Para que F (n) sea O(log4 (n)) hace falta
encontrar un k constante tal que se cumpla la siguiente desigualdad
para todo n algn n0 .
u
(1.2.33)
(1.2.34)
(1.2.35)
(1.2.36)
(1.2.37)
(1.2.38)
CAP
ITULO 1. TIEMPO DE EJECUCION
1.3.
Prog. III
1.3.1.
Expresin constante
o
1.3.2.
Grupo de constantes
1.3.3.
Secuencias
1.3.4.
Condicionales
Dado un condicional if, el tiempo es el peor caso entre todos los caminos
posibles de ejecucin.
o
1.3.5.
for y while
1.3.6.
1.3. ANALISIS DE ALGORITMOS Y RECURRENCIAS
Prog. III
(1.3.1)
(1.3.2)
(1.3.3)
(1.3.4)
(1.3.5)
(1.3.6)
(1.3.7)
CAP
ITULO 1. TIEMPO DE EJECUCION
Prog. III
T (n) = c1 +
(c2 )
(1.3.8)
x=1
1.3.7.
Llamadas recursivas
Las llamadas recursivas se reemplazan por la denicion de tiempo recursiva. Las deniciones recursivas son funciones denidas por partes, teniendo
por un lado el caso base y por el otro el caso recursivo.
1.3.8.
Ejemplo 5, iterativo
n
i=1 .
Linea 4: c2 .
Linea 6: c3 .
T (n) = c1 + (
c2 ) + c3
(1.3.9)
i=1
(1.3.10)
(1.3.11)
1.3. ANALISIS DE ALGORITMOS Y RECURRENCIAS
1.3.9.
Prog. III
Ejemplo 6, recursivo
1 int r e c 1 ( int n ){
2
i f ( n <= 1 )
3
return 3 ;
4
else
5
return 1 + r e c 1 ( n1) * r e c 1 ( n 1);
6 }
Las funciones recursivas se denen por partes, donde cada parte se resuelve de forma similar a un codigo iterativo:
T (n) =
c1
2T (n 1) + c2
n1
n>1
T (n) = 2T (n 1) + c2 , n > 1
T (n 1) = 2T (n 2) + c2 , n 1 > 1
T (n 2) = 2T (n 3) + c2 , n 2 > 1
(1.3.12)
(1.3.13)
(1.3.14)
Segundo, se expande cada trmino tres o cuatro veces, las que sean necesae
rias para descubrir la forma en la que los diferentes trminos van cambiando:
e
T (n) = 2T (n 1) + c2
T (n) = 2(2T (n 2) + c2 ) + c2
T (n) = 2(2(2T (n 3) + c2 ) + c2 ) + c2
T (n) = 2(22 T (n 3) + 2c2 + c2 ) + c2
T (n) = 23 T (n 3) + 22 c2 + 2c2 + c2 , n 3 1
(1.3.15)
(1.3.16)
(1.3.17)
(1.3.18)
(1.3.19)
T (n) = 2k T (n k) +
2i c2
i=0
(1.3.20)
CAP
ITULO 1. TIEMPO DE EJECUCION
Prog. III
nk =1
k =n1
(1.3.21)
(1.3.22)
n11
2i c2
(1.3.23)
2i c2
(1.3.24)
i=0
n2
T (n) = 2n1 c1 +
i=0
n2
T (n) = 2n1 c1 + c2
2i
(1.3.25)
T (n) = 2n1 c1 + c2 (2
1)
n1
n1
T (n) = 2 c1 + 2 c2 c2
T (n) = 2n1 (c1 + c2 ) c2
(1.3.26)
(1.3.27)
(1.3.28)
i=0
n2+1
1.3.10.
Ejemplo 7, recursivo
T (n) =
c
2n + T (n/2)
n=1
n2
k=0
1
1
=2 n
k
2
2
Deniciones parciales:
T(
T(
T (n) = 2n + T (n/2)
2n
n
n
T( ) =
+T 2
2
2
2
Desarrollo:
21
n
n
2n
)= 2 +T 3
2
2
2
2
n
2n
n
)= 3 +T 4
3
2
2
2
1.3. ANALISIS DE ALGORITMOS Y RECURRENCIAS
T (n) = 2n + T (n/2)
2n
n
T (n) = 2n +
+T 2
2
2
2n
2n
n
T (n) = 2n +
+
+T 3
2
22
2
2n 2n
2n
n
T (n) = 2n +
+ 2 +
+T 4
2
2
23
2
3
T (n) =
i=0
3
Prog. III
(1.3.29)
(1.3.30)
(1.3.31)
(1.3.32)
n
2n
+T 4
i
2
2
(1.3.33)
1
n
+T 4
i
2
2
(1.3.34)
T (n) = 2n
i=0
Paso general k:
k1
T (n) = 2n
i=0
1
n
+T k
i
2
2
(1.3.35)
Caso base:
n
= 1 n = 2k log n = k
k
2
log n1
T (n) = 2n
i=0
1
n
+ T log n
i
2
2
log n1
T (n) = 2n
i=0
T (n) = 2n 2
1
+c
2i
+c
2log n1
2n
T (n) = 4n log n1 + c
2
(1.3.36)
(1.3.37)
(1.3.38)
(1.3.39)
(1.3.40)
22
CAP
ITULO 1. TIEMPO DE EJECUCION
T (n) = 4n
2n
(2log n )/2
Prog. III
+c
2n
+c
(n)/2
4n
T (n) = 4n
+c
n
T (n) = 4n 4 + c
T (n) = 4n
1.3.11.
(1.3.41)
(1.3.42)
(1.3.43)
(1.3.44)
1
n
8T ( ) + n3
2
n=1
n2
Soluciones parciales:
n
T (n) = 8T ( ) + n3
2
n
n
n
T ( ) = 8T ( ) + ( )3
2
4
2
n
n
n
T ( ) = 8T ( ) + ( )3
4
8
4
n
n
n
T ( ) = 8T ( ) + ( )3
8
16
8
(1.3.45)
(1.3.46)
(1.3.47)
(1.3.48)
Desarrollo:
n
T (n) = 8T ( ) + n3
2
n
n
T (n) = 8(8T ( ) + ( )3 ) + n3
4
2
n
n 3
n
T (n) = 8(8(8T ( ) + ( ) ) + ( )3 ) + n3
8
4
2
n
n 3
n 3
n
T (n) = 8(8(8(8T ( ) + ( ) ) + ( ) ) + ( )3 ) + n3
16
8
4
2
n
n 3
n 3
n 3
T (n) = 8(8(82 T ( ) + 8( ) + ( ) ) + ( ) ) + n3
16
8
4
2
n 3
n 3
n 3
n
T (n) = 8(83 T ( ) + 82 ( ) + 8( ) + ( ) ) + n3
16
8
4
2
n
n
n
n
T (n) = 84 T ( ) + 83 ( )3 + 82 ( )3 + 8( )3 + n3
16
8
4
2
n 3
n3 = 80 ( 0 )
2
23
(1.3.49)
(1.3.50)
(1.3.51)
(1.3.52)
(1.3.53)
(1.3.54)
(1.3.55)
(1.3.56)
1.3. ANALISIS DE ALGORITMOS Y RECURRENCIAS
T (n) = 84 T (
n
n
n
n
n
) + 83 ( 3 )3 + 82 ( 2 )3 + 81 ( 1 )3 + 80 ( 0 )3
24
2
2
2
2
3
n
T (n) = 8 T ( 4 ) +
2
4
i=0
Prog. III
(1.3.57)
n
8i ( i )3
2
(1.3.58)
n
8i ( i )3
2
(1.3.59)
Caso k:
n
T (n) = 8 T ( k ) +
2
k1
i=0
Caso base:
n
= 1 n = 2k log n = log 2k = k
2k
k = log n
log n
T (n) = 8
T(
n
2log n
log n1
T (n) = 8
(1.3.61)
n3
)
(2i )3
(1.3.62)
(23 )i n3
)
23i
(1.3.63)
23i n3
)
23i
(1.3.64)
i=0
log n1
8i (
i=0
log n1
log n
n
8i ( i )3
2
)+
n
T (n) = 8log n T ( ) +
n
T (1) +
(
i=0
log n1
log n
T (n) = 8
T (1) +
(1.3.60)
(
i=0
log n1
T (n) = 8
log n
(n3 )
T (1) +
(1.3.65)
i=0
(1.3.66)
(1.3.67)
(1.3.68)
(1.3.69)
T (n) = n3 + n3 log n
(1.3.70)
24
CAP
ITULO 1. TIEMPO DE EJECUCION
1.4.
Prog. III
Otros ejemplos
1.4.1.
Ejemplo 9
Planteo de la recurrencia
c1
T (n) =
n
i=1
i
j=1 c2
n
+ 4T ( )
2
n=1
n2
c2 =
i=1 j=1
ic2 = c2
i=1
i=
i=1
c2 n(n + 1)
c2
= (n2 + n)
2
2
c1
c2 2
n
(n + n) + 4T ( )
2
2
Desarrollo de la recurrencia:
T (n) =
T (n) =
c2 2
n
(n + n) + 4T ( )
2
2
25
(1.4.1)
n=1
n2
(1.4.2)
Prog. III
c2 2
(n + n) + 4
2
=
c2
2
n
2
n
2
c2
c2 2
(n + n) + 4
2
2
n
2
n
22
+ 4T
n
2
+ 42 T
(1.4.3)
n
22
(1.4.4)
c2 2
c2
n 2
n
(n + n) + 4
+
+
2
2
2
2
c2
n 2
n
n
+ 4T 3
42
+ 2
2
2
2
2
2
(1.4.5)
c2 2
c2
n 2
n
(n + n) + 4
+
+
2
2
2
2
c2
n 2
n
n
42
+ 43 T 3
+ 2
2
2
2
2
2
(1.4.6)
c2
c2 2
n 2
n
(n + n) + 4
+
+
2
2
2
2
c2
n 2
n
42
+ 2
+
2
22
2
n 2
n
n
c2
43
+ 3
+ 4T 4
3
2
2
2
2
(1.4.7)
c2
n 2
c2 2
n
(n + n) + 4
+
+
2
2
2
2
c2
n 2
n
42
+ 2
+
2
2
2
2
n 2
n
n
c2
+ 3
+ 44 T 4
43
2
23
2
2
(1.4.8)
c2
=
2
=
c2
2
c2
=
2
4w
w=0
n
2w
n
2w
+ 44 T
n
24
(1.4.9)
4w
n2
(2w )2
+ 4w
n
2w
+ 44 T
n
24
(1.4.10)
22w
n2
22w
+ 22w
n
2w
+ 44 T
n
24
(1.4.11)
w=0
3
w=0
c2
2
n2 + 2w (n) + 44 T
w=0
26
n
24
(1.4.12)
CAP
ITULO 1. TIEMPO DE EJECUCION
c2
T (n) =
2
c2
n +
2
w=0
2w n + 44 T
w=0
Prog. III
n
24
(1.4.13)
Paso general k:
c2
T (n) =
2
k1
c2
n +
2
w=0
k1
2w n + 4k T
w=0
n
2k
(1.4.14)
Paso base:
n
=1
2k
n = 2k
log2 n = log2 (2k )
log2 n = k
log (n)1
(1.4.15)
(1.4.16)
(1.4.17)
(1.4.18)
log (n)1
c2 2
n
c2 2
n2 +
2w n + 4log2 n T log n
T (n) =
2 w=0
2 w=0
2 2
c2
n
c2
= n2 log2 (n) + (log2 (n) + 1)n + 4log2 n T log n
2
2
2 2
log2 n
2 log2 n
log2 n 2
4
= (2 )
= (2
) = n2
c2
c2
= n2 log2 (n) + (log2 (n) + 1)n + n2 T (1)
2
2
c2 2
c2
c2
T (n) = n log2 (n) + n log2 (n) + n + c1 n2
2
2
2
(1.4.19)
(1.4.20)
(1.4.21)
(1.4.22)
(1.4.23)
(1.4.24)
(1.4.25)
(1.4.26)
Prog. III
1.4.2.
Ejemplo 10
Antes de empezar
Para plantear inicialmente este ejercicio hace falta analizar el programa.
Una estrategia interesante para resolver este tipo de ejercicios consiste en
reescribir los l
mites de los bucles, a n de conseguir un programa que se
ejecute la misma cantidad de veces que el original y calcule los mismos valores
con el mismo resultado, pero que sea ms fcil para analizar.
a a
Por ejemplo, los programas F1 y F2 son equivalentes en cuanto al valor
calculado y cantidad de veces que se ejecuta cada bucle, solo var en sus
an
constantes:
28
CAP
ITULO 1. TIEMPO DE EJECUCION
Prog. III
(1.4.28)
Prog. III
El for con
ndice j se ejecuta tantas veces como vale la variable sum1.
Dado que el valor de la variable sum1 va cambiando a medida que se
ejecuta el programa, no es correcto decir que ste for se ejecuta 2 * n
e
veces, porque n siempre vale lo mismo pero sum1 no.
El for con
ndice k se ejecuta sum1 - j + 1 veces.
Dado que el
ndice i del primer for no se utiliza sino solo para contar
(y no aparece en ningn otro lugar del programa) podemos cambiar el
u
primer for (con
ndice i) por esto otro:
for ( int i =1; i <= ( 2 * n 1 ) ; i ++) { . . .
Con este cambio conseguimos que la variable i tome el mismo valor
que la variable sum1, manteniendo que ste for se ejecute la misma
e
cantidad de veces que el for original.
A partir de este anlisis, podemos denir la funcin de tiempo:
a
o
2n1
T (n) =
c1
(1.4.29)
(i j + 1)
(1.4.30)
T (n) = c1
i=1 j=1
2n1
T (n) = c1
i=1
j=1
i=1
(1.4.33)
T (n) = c1
i=1
i2 =
j=1
1
1
i2 i2 i + i
2
2
2n1
1
T (n) = c1
2
(1.4.31)
(1.4.32)
i=1
T (n) = c1
i(i + 1)
+i
2
i2
2n1
j+
j=1
2n1
T (n) = c1
i=0
1 2 1
i + i
2
2
2n1
2n1
2
i +
i=1
(1.4.34)
i
i=1
n(n + 1)(2n + 1)
6
30
(1.4.35)
CAP
ITULO 1. TIEMPO DE EJECUCION
2n1
2n
i2 =
i2
i=1
T (n) = c1
1
2
(2n)2
(1.4.36)
i=1
(2n)((2n) + 1)(2(2n) + 1)
(2n 1)(2n)
(2n)2 +
6
2
(1.4.37)
(4n2 + 2n)(4n + 1)
4n2 2n
4n2 +
6
2
(1.4.38)
(1.4.39)
16 3 4 2 8 2 2
4
2
n + n + n + n 4n2 + n2 n
6
6
6
6
2
2
(1.4.40)
T (n) = c1
1
T (n) = c1
2
T (n) = c1
Prog. III
1
2
1
2
1
2
16 3 2
n n
6
3
(1.4.41)
4
2
T (n) = c1 n3 c1 n
3
3
(1.4.42)
T (n) = c1
31
(1.4.46)
1.5.
Prog. III
c = nc
(1.5.1)
c = (n k + 1)c
(1.5.2)
i=1
n
i=k
n
n(n + 1)
2
(1.5.3)
n(n + 1)(2n + 1)
6
(1.5.4)
i=
i=1
n
i2 =
i=0
n
n(n + 1)
2
i3 =
i=0
n
i4 =
i=0
i=k
(1.5.6)
k1
f (i)
f (i) =
(1.5.5)
f (i)
(1.5.7)
2i = 2n+1 1
(1.5.8)
1 an+1
1a
(1.5.9)
logc a
logc b
(1.5.10)
i=1
n
i=1
i=0
n
ai =
i=0
logb a =
a
= log a log b
b
log (a b) = log a + log b
logb (ba ) = blogb a = a
c
ab = abc = (ac )b
log
32
(1.5.11)
(1.5.12)
(1.5.13)
(1.5.14)
Cap
tulo 2
Listas
33
2.1. LOS PARES DEL FARAON
2.1.
Prog. III
2.1.1.
34
CAP
ITULO 2. LISTAS
2.1.2.
Prog. III
Implementacin Java
o
1 int c o n t a r ( L i s t a D e E n t e r o s L) {
2
int c a n t i d a d = 0 ;
3
4
L . comenzar ( ) ;
5
while ( ! L . f i n ( ) ) {
6
i f ( ( L . elemento ( ) % 2 ) == 0 )
7
c a n t i d a d ++;
8
L . proximo ( ) ;
9
}
10
11
return c a n t i d a d ;
12 }
35
2.2. PILAMIN
2.2.
Prog. III
PilaMin
(a) Implementar una clase PilaDeEnteros donde todas las operaciones sean
de tiempo constante O(1).
(b) Implementar una subclase PilaMin que permita obtener el m
nimo elemento presente en la estructura, tambin en tiempo constante O(1).
e
1
2
3
4
5
6
7
8
9
10
class PilaDeEnteros {
public void poner ( int e ) { . . . }
public int s a c a r ( ) { . . . }
public int tope ( ) { . . . }
public boolean e s V a c i a ( ) { . . . }
}
c l a s s PilaMin extends P i l a D e E n t e r o s {
public int min ( ) { . . . }
}
2.2.1.
CAP
ITULO 2. LISTAS
Prog. III
En una lista enlazada simple, insertar y eliminar en el comienzo es tambin de tiempo constante, ya que solo hace falta hacer los enganches del
e
primer nodo de la estructura junto con la referencia al primer elemento, sin
importar cuntos elementos contiene la estructura.
a
2.2.2.
class PilaDeEnteros {
private L i s t a D e E n t e r o s E n l a z a d a L = new
ListaDeEnterosEnlazada ( ) ;
public void poner ( int e ) {
L . comenzar ( ) ;
L . a g r e g a r ( e ) ; / * Tiempo c t e . * /
}
public int s a c a r ( ) {
int x ;
L . comenzar ( ) ;
x = L . elemento ( ) ;
L . e l i m i n a r ( ) ; / * Tiempo c t e . * /
}
public int tope ( ) {
L . comenzar ( ) ;
return L . elemento ( ) ; / * Tiempo c t e . * /
}
public boolean e s V a c i a ( ) {
return (L . tamanio ( ) == 0 ) ; / * Tiempo c t e . * /
}
}
2.2.3.
2.2. PILAMIN
Prog. III
38
CAP
ITULO 2. LISTAS
Prog. III
/ * Version f i n a l c o r r e c t a . * /
c l a s s PilaMin extends P i l a D e E n t e r o s {
private s t a t i c int MIN( int a , int b ) {
return ( a < b ) ? a : b ;
}
P i l a D e E n t e r o s minimos = new P i l a D e E n t e r o s ( ) ;
public void poner ( int e ) {
i f ( esVacia () )
minimos . poner ( e ) ;
else
minimos . poner (MIN( e , minimos . tope ( ) ) ) ;
super . poner ( e ) ;
}
public int s a c a r ( ) {
minimos . s a c a r ( ) ;
return super . s a c a r ( ) ;
}
public int min ( ) {
return minimos . tope ( ) ;
}
}
39
2.2. PILAMIN
Prog. III
40
Cap
tulo 3
41
3.1.
Prog. III
o
o
el valor de la expresin. El arbol ya se encuentra construido, es de String y
o
la funcin ser:
o
a
f l o a t e v a l u a r ( A r b o l B i n a r i o <S t r i n g > a ) { . . . }
Ejemplo: Dado el arbol 2 + 3 * 4, la funcin deber devolver el valor 14.
o
a
3.1.1.
o
e
a
de expresin, la forma ms fcil y directa de resolverlo es de forma recursiva.
o
a a
Si el rbol est vac se dispara un NullPointerException en la primer
a
a
o
llamada, pero dado que el rbol ya viene correctamente construido como un
a
arbol de expresin, todos los nodos operadores tendrn dos hijos, y los nodos
o
a
de valores sern hojas.
a
3.1.2.
Implementacin Java
o
1 f l o a t e v a l u a r ( A r b o l B i n a r i o <S t r i n g > A) {
2
S t r i n g d = A. getDatoRaiz ( ) ;
3
A r b o l B i n a r i o <S t r i n g > I = A. g e t H i j o I z q u i e r d o ( ) ;
4
A r b o l B i n a r i o <S t r i n g > D = A. g e t H i j o D e r e c h o ( ) ;
5
6
i f ( d . e q u a l s ( + ) )
7
return e v a l u a r ( I ) + e v a l u a r (D) ;
8
i f ( d . e q u a l s ( ) )
9
return e v a l u a r ( I ) e v a l u a r (D) ;
10
i f (d . equals ( * ) )
11
return e v a l u a r ( I ) * e v a l u a r (D) ;
12
i f ( d . e q u a l s ( / ) )
13
return e v a l u a r ( I ) / e v a l u a r (D) ;
14
15
return F l o a t . p a r s e F l o a t ( d ) ;
16 }
42
CAP
ITULO 3. ARBOLES BINARIOS Y GENERALES
3.2.
Prog. III
M
nimo del Nivel
3.2.1.
de nivel actual. Cuando se llega al nivel esperado hay que devolver el valor
actual, y cuando se regresa de la recursin hay que comparar los minimos
o
entre los hijos izquierdo y derecho del nodo actual.
En la forma iterativa hace falta recorrer por niveles el arbol, contando el
nivel actual con la marca de null. Cuando se llega al nivel esperado hay que
buscar entre todos los valores desencolados el m
nimo de ellos. Una vez que
se terminaron los elementos o se lleg a un nivel ms que el buscado hay que
o
a
cortar la bsqueda.
u
En ambos casos, hace falta vericar que el nivel realmente exista. Una
forma de transmitirlo es devolviendo null cuando no se encontr el valor.
o
Esto solo se puede cuando se usa Integer como tipo de datos; usando int
como tipo de datos de retorno no es posible devolver null.
En el caso de usar int se puede usar la constante Integer.MAX VALUE
para indicar que el valor no se encontr.
o
En Java, el operador ternario signo de pregunta ?: es un if reducido.
La parte de la izquierda es la condicin, cuando es true se devuelve el valor
o
del medio, y cuando es false se devuelve lo que hay a la derecha del dos
puntos.
Por ejemplo, la siguiente funcin devuelve el mximo entre los valores
o
a
recibidos por parmetro:
a
1
2
3
43
3.2. M
INIMO DEL NIVEL
3.2.2.
Prog. III
3.2.3.
44
CAP
ITULO 3. ARBOLES BINARIOS Y GENERALES
3.2.4.
Prog. III
45
3.3.
Prog. III
Trayectoria Pesada
3.3.1.
3.3.2.
Existen diferentes maneras de recorrer rboles, cada cual con sus ventajas
a
y desventajas. Un recorrido recursivo puede ser interesante, en especial el
preorden o inorden. Cualquiera de stos se puede aplicar al ejercicio. Por
e
ejemplo, a continuacin1 se puede ver el recorrido preorden.
o
3.3.3.
CAP
ITULO 3. ARBOLES BINARIOS Y GENERALES
Prog. III
3.3.4.
Prog. III
3.3.5.
Detalles de implementacin
o
Modularizacin
o
Modularizar y separar el cdigo en diferentes funciones o mtodos suele
o
e
ser una buena idea. Hasta ahora vimos que el ejercicio se puede separar en
dos mtodos. Sin embargo, se pide devolver los valores de todas las hojas,
e
por lo que hace falta que el mtodo principal del ejercicio tenga como tipo de
e
retorno ListaGenerica<T> (o la estructura elegida). Esto puede complicar la
implementacin del recorrido preorden, por lo que puede ser de mucha ayuda
o
tener otro mtodo aparte que se encargue del recorrido recursivo. Una buena
e
forma de modularizar este ejercicio puede ser como el siguiente ejemplo:
48
CAP
ITULO 3. ARBOLES BINARIOS Y GENERALES
Prog. III
1 class EjercicioCinco {
2
public s t a t i c L i s t a G e n e r i c a <I n t e g e r >
C a l c u l a r T r a y e c t o r i a ( A r b o l B i n a r i o <T> A) {
3
L i s t a G e n e r i c a <I n t e g e r > l i s t a = new
L i s t a E n l a z a d a G e n e r i c a <I n t e g e r >() ;
4
5
R e c o r r i d o (A, 1 , 0 , l i s t a ) ;
6
7
return l i s t a ;
8
}
9
10
private s t a t i c void R e c o r r i d o ( A r b o l B i n a r i o <T> A,
int N, int V, L i s t a G e n e r i c a <I n t e g e r > l i s t a ) {
11
// Metodo d e l r e c o r r i d o R p r e o r d e n r e c u r s i v o .
12
i f ( ! A. e s V a c i o ( ) ) {
13
// . . .
14
}
15
}
16
17
private s t a t i c void P r o c e s a r ( A r b o l B i n a r i o <T> A,
int N, int V, L i s t a G e n e r i c a <I n t e g e r > l i s t a ) {
18
// . . .
19
}
20 }
esHoja()
Prog. III
1 c l a s s A r b o l B i n a r i o <T> {
2
public boolean esHoja ( ) {
3
return ! t i e n e H i j o I z q u i e r d o ( ) && !
tieneHijoDerecho () ;
4
}
5
6
public boolean t i e n e H i j o I z q u i e r d o ( ) {
7
return g e t R a i z ( ) . g e t H i j o I z q u i e r d o ( ) != null ;
8
}
9
10
public boolean t i e n e H i j o D e r e c h o ( ) {
11
return g e t R a i z ( ) . g e t H i j o D e r e c h o ( ) != null ;
12
}
13 }
public y private
En Java, la forma que se tiene de abstraer y encapsular cdigo y datos
o
es mediante los especicadores de acceso. Dos de ellos son public y
private, que permiten denir desde qu parte del cdigo se puede invocar
e
o
un mtodo o acceder a una variable.
e
En el caso de este ejercicio, es importante que el mtodo principal del
e
recorrido sea public a n de que los usuarios del ArbolBinario lo puedan
utilizar. Por otro lado, tener los mtodos auxiliares como private permite
e
que los detalles de implementacin permanezcan ocultos, dejando la libertad
o
que en un futuro sea posible modicar el cdigo y los detalles de implemeno
tacin teniendo el menor impacto en el mantenimiento del resto del cdigo
o
o
donde se utilizan estas llamadas.
Clases abstractas
El operador new solo puede ser usado para instanciar clases que no
sean abstract. Por ejemplo, el siguiente programa no es correcto, ya que el
operador new se est usando para instanciar una clase abstract.
a
1 public abstract c l a s s X {
2
public X( ) {
3
// . . .
4
}
5
6
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
50
CAP
ITULO 3. ARBOLES BINARIOS Y GENERALES
Prog. III
7
X y = new X( ) ; // Error !
8
}
9 }
En particular, no es posible crear una instancia de ListaGenerica<T>,
ya que esta es una clase abstract. Es necesario instanciar una subclase que
no sea abstract. Por ejemplo, ListaEnlazadaGenerica<T>.
1 public void f ( ) {
2
L i s t a G e n e r i c a <I n t e g e r > L = new
L i s t a E n l a z a d a G e n e r i c a <I n t e g e r >() ;
3 }
3.3.6.
Prog. III
CAP
ITULO 3. ARBOLES BINARIOS Y GENERALES
Prog. III
1 c l a s s A r b o l B i n a r i o <T> {
2
public L i s t a G e n e r i c a <I n t e g e r > T r a y e c t o r i a (
A r b o l B i n a r i o <T> A) {
3
// Ac hay dos r b o l e s . t h i s y A .
a
a
4
}
5 }
La solucin a esto puede ser:
o
a) Indicar los mtodos de recorrido como static,
e
b) Quitar el parmetro y hacer el recorrido del arbol con this.
a
c) Implementar los mtodos en una clase diferente a ArbolBinario,
e
por ejemplo dentro de la clase EjercicioCinco.
6. Preguntar por la existencia del hijo izquierdo o derecho a partir del
valor devuelto por getHijoIzquierdo() de ArbolBinario.
1 c l a s s A r b o l B i n a r i o <T> {
2
public A r b o l B i n a r i o <T> g e t H i j o I z q u i e r d o ( ) {
3
return new A r b o l B i n a r i o <T>( g e t R a i z ( ) .
getHijoIzquierdo () ) ;
4
}
5 }
De acuerdo a la denicin vista en clase de ArbolBinario, los mtoo
e
dos getHijoIzquierdo y getHijoDerecho de ArbolBinario nunca devuelven null, y por lo tanto la siguiente pregunta nunca va a ser True,
porque el operador new nunca devuelve null.
1 i f ( a r b o l . g e t H i j o I z q u i e r d o ( )==null ) {
2
// Nunca puede s e r True .
3 }
Lo ideal en este caso es utilizar los mtodos tieneHijoIzquierdo y
e
tieneHijoDerecho, implementados dentro de la clase ArbolBinario
tal como se muestra en la seccin Detalles de implementacin.
o
o
7. Variables en null. El siguiente cdigo dispara siempre un error de
o
NullPointerException. Si la condicin del if da True entonces lista
o
es null, y de ninguna forma es posible utilizar la variable lista porque justamente su valor es null.
53
Prog. III
1 i f ( l i s t a==null )
2 {
3
l i s t a . a g r e g a r ( sum ) ;
4 }
8. Preguntar si this es null. El lenguaje Java garantiza que this
jams pueda ser null, ya que al momento de invocar un mtodo de
a
e
instancia en una variable con referencia null, se dispara un error de
NullPointerException.
54
CAP
ITULO 3. ARBOLES BINARIOS Y GENERALES
3.4.
Prog. III
o
donde la ra es el pariente inmigrante que lleg en barco desde un pa lejano,
z
o
s
y la relacin de hijos son los hijos de cada persona.
o
Escribir en Java un mtodo que, dado un arbol general de Strings y
e
3.4.1.
Explicacin General
o
el de mayor nivel.
3.4.2.
Versin Recursiva
o
1 class X {
2
public s t a t i c S t r i n g ancestroComun ( ArbolGeneral<
S t r i n g > A, S t r i n g Nom1, S t r i n g Nom2) {
3
i f (A. e s V a c i o ( ) )
4
return null ;
5
6
boolean t i e n e N 1 = f a l s e , t i e n e N 2 = f a l s e ;
7
L i s t a G e n e r i c a <ArbolGeneral<S t r i n g >> L = A. g e t H i j o s
() ;
8
S t r i n g a n c e s t r o = null ;
55
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// S i no hay h i j o que s e a a n c e s t r o me f i j o s i e l
nodo a c t u a l e s a n c e s t r o ; donde N1 y N2 ambos
e s t e n en a l g u n o de mis sub r b o l e s .
a
L . comenzar ( ) ;
while ( ! L . f i n ( ) ) {
t i e n e N 1 = t i e n e N 1 | | e s H i j o (L . elemento ( ) , Nom1) ;
t i e n e N 2 = t i e n e N 2 | | e s H i j o (L . elemento ( ) , Nom2) ;
i f ( t i e n e N 1 && t i e n e N 2 )
break ;
L . proximo ( ) ;
}
i f ( t i e n e N 1 && t i e n e N 2 )
return A. getDatoRaiz ( ) ;
return null ;
}
private s t a t i c boolean e s H i j o ( ArbolGeneral<S t r i n g > A,
S t r i n g dato ) {
// D e v u e l v e True s i a l g u n nodo d e l s u b a r b o l t o t a l
p o s e e como d a t o e l parametro Dato
i f (A. e s V a c i o ( ) )
return f a l s e ;
i f (A. getDatoRaiz ( ) . e q u a l s ( dato ) )
return true ;
56
CAP
ITULO 3. ARBOLES BINARIOS Y GENERALES
42
43
44
45
46
47
48
49
50
51
}
52 }
Prog. III
L i s t a G e n e r i c a <ArbolGeneral<S t r i n g >> L = A. g e t H i j o s
() ;
L . comenzar ( ) ;
while ( ! L . f i n ( ) ) {
i f ( e s H i j o (L . elemento ( ) , dato ) ) {
return true ;
}
L . proximo ( ) ;
}
return f a l s e ;
57
58
Cap
tulo 4
Arboles AVL
59
4.1.
Prog. III
4.1.1.
Hay que descartar las palabras repetidas y contar las diferentes. Eso se
logra recorriendo la lista de entrada; por cada palabra agregarla al arbol solo
4.1.2.
Implementacin Java
o
60
CAP
ITULO 4. ARBOLES AVL
4.2.
Prog. III
Pepe y Alicia
Pepe y Alicia quieren saber cules son sus intereses en comn. Para ello,
a
u
cada uno arm una lista de intereses, pero llegaron a tener miles cada uno.
o
Implemente en Java un programa que dadas dos listas de String devuelva
de forma eciente una lista con los intereses en comn, sin elementos repetiu
dos. Los intereses de cada uno pueden estar repetidos, pero el resultado debe
tener uno solo de cada tipo. No hace falta implementar las estructuras.
Ejemplo: A Pepe le gusta [A, B, C, A, B] y a Alicia [A, D, A]. Sus intereses en comn son: [A].
u
L i s t a G e n e r i c a <S t r i n g > interesesComun ( L i s t a G e n e r i c a <
S t r i n g > P , L i s t a G e n e r i c a <S t r i n g > A) { . . . }
4.2.1.
Prog. III
Hace falta utilizar dos rboles AVL. El primer arbol contendr los elemena
a
tos de la primer lista, permitiendo conocer de forma eciente qu elemento
e
se encuentran en sta lista. Primero, hace falta guardar los elementos de la
e
primer lista en el primer arbol AVL sin repeticin. Luego, recorriendo la se
o
gunda lista se pregunta si cada elemento de esta se encuentra en el primer
arbol pero no en el segundo. En caso de que se cumpla la condicin, se inserta
o
en el segundo arbol AVL y adems en una lista temporal.
a
La lista temporal contendr los elementos que se encuentran en ambas
a
listas iniciales, sin repeticin, y ser construida en tiempo O(n log n), con
o
a
n siendo la suma de la cantidad de elementos de ambas listas iniciales. El
segundo arbol contendr los elementos que se encuentran en la lista temporal,
a
permitiendo una bsqueda eciente para vericar si ya fueron agregados a la
u
lista resultante.
4.2.2.
Implementacin Java
o
1 class I n t e r e s e s {
2
L i s t a G e n e r i c a <S t r i n g > interesesComun ( L i s t a G e n e r i c a <
S t r i n g > P , L i s t a G e n e r i c a <S t r i n g > A) {
3
L i s t a G e n e r i c a <S t r i n g > r e s u l t a d o = new
L i s t a E n l a z a d a G e n e r i c a <S t r i n g >() ;
4
ArbolAVL<S t r i n g > lasDePepe = new ArbolAVL<S t r i n g >()
;
5
ArbolAVL<S t r i n g > enComun = new ArbolAVL<S t r i n g >() ;
6
7
P . comenzar ( ) ;
8
while ( ! P . f i n ( ) ) {
9
i f ( ! lasDePepe . i n c l u y e (P . elemento ( ) ) ) {
10
lasDePepe . a g r e g a r (P . elemento ( ) ) ;
11
}
12
P. siguiente () ;
13
}
14
15
A. comenzar ( ) ;
16
while ( ! A. f i n ( ) ) {
17
i f ( lasDePepe . i n c l u y e (A. elemento ( ) ) && ! enComun .
i n c l u y e (A. elemento ( ) ) ) {
18
enComun . a g r e g a r (A. elemento ( ) ) ;
19
r e s u l t a d o . a g r e g a r (A. elemento ( ) ) ;
20
}
62
CAP
ITULO 4. ARBOLES AVL
Prog. III
21
A. s i g u i e n t e ( ) ;
22
}
23
24
return r e s u l t a d o ;
25
}
26 }
63
Prog. III
64
Cap
tulo 5
Grafos
65
5.1.
Prog. III
recursin.
o
A diferencia del DFS, en un recorrido BFS no se evalan todas las posibles
u
combinaciones de caminos. En un DFS, cada vrtice puede ser visitado ms
e
a
de una vez, mientras que en un BFS cada vrtice puede ser visitado a lo sumo
e
una unica vez.
Por un lado, esto permite que en general los recorridos BFS sean ms
a
ecientes que un recorrido DFS. Por otro lado, no siempre es posible resolver
cualquier recorrido con un BFS, no dejando otra opcin que hacerlo aplicando
o
un recorrido DFS.
La forma general de un recorrido BFS es:
1 void BFS( V e r t i c e V) {
66
CAP
ITULO 5. GRAFOS
2
Prog. III
3
4
5
6
7
8
9
10
11
12
13
14
15
16 }
while ( ! C. e s V a c i a ( ) ) {
V e r t i c e W = C. s a c a r ( ) ;
L i s t a G e n e r i c a ADY = W. o b t e n e r A d y a c e n t e s ( ) ;
for (ADY. comenzar ( ) ; !ADY. f i n ( ) ; ADY. proximo ( ) ) {
A r i s t a E = ADY. elemento ( ) ;
i f ( ! v i s i t a d o s [E. verticeDestino () . posicion () ] ) {
v i s i t a d o s [ E . v e r t i c e D e s t i n o ( ) . p o s i c i o n ( ) ] = true
;
C. poner (E . v e r t i c e D e s t i n o ( ) ) ;
}
}
}
Prog. III
v i s i t a d o s [V. p o s i c i o n ( ) ] = true ;
i f ( d i s t a n c i a s [V. p o s i c i o n ( ) ] > peso ) {
d i s t a n c i a s [V. p o s i c i o n ( ) ] = peso ;
}
L i s t a G e n e r i c a ADY = V. o b t e n e r A d y a c e n t e s ( ) ;
for (ADY. comenzar ( ) ; !ADY. f i n ( ) ; ADY. proximo ( ) ) {
A r i s t a E = ADY. elemento ( ) ;
i f ( ! v i s i t a d o s [E. verticeDestino () . posicion () ] )
DFS(E . v e r t i c e D e s t i n o ( ) , peso + E . peso ( ) ) ;
}
v i s i t a d o s [V. p o s i c i o n ( ) ] = f a l s e ;
68
CAP
ITULO 5. GRAFOS
5.2.
Prog. III
El n mero Bacon
u
Hace algunos aos en una entrevista, Kevin Bacon coment que l hab
n
o
e
a
actuado con la mayor de los actores de Hollywod, ya sea en la misma
a
pel
cula o indirectamente con otro actor.
Ah naci el Nmero de Bacon, con la idea de establecer cual era la
o
u
distancia entre Bacon y el resto de los actores de Hollywood2 . Los actores
que hab actuado en alguna pel
an
cula junto a Bacon tienen el nmero 1, los
u
que actuaron en alguna pel
cula junto a alguien que actu con Bacon tienen
o
el nmero 2, y as sucesivamente.
u
69
5.2. EL NUMERO BACON
5.2.1.
Prog. III
The Oracle Of Bacon3 es una pgina web que permite ver cul es la
a
a
relacin entre dos actores a partir de las pel
o
culas que ambos actuaron. Cmo
o
funciona?
5.2.2.
5.2.3.
1 c l a s s BFS {
2
/ * Buscar e l v e r t i c e d e l a c t o r * /
3
private V e r t i c e <S t r i n g > b u s c a r A c t o r ( Grafo<S t r i n g > G,
String actor ) {
4
L i s t a G e n e r i c a <V e r t i c e <S t r i n g >> v e r t i c e s = G.
listaDeVertices () ;
5
v e r t i c e s . comenzar ( ) ;
6
while ( ! v e r t i c e s . f i n ( ) ) {
7
V e r t i c e <S t r i n g > v = v e r t i c e s . elemento ( ) .
verticeDestino () ;
8
i f ( v . dato ( ) . e q u a l s ( a c t o r ) )
9
return v ;
10
v e r t i c e s . proximo ( ) ;
11
}
12
return null ;
13
}
14
15
/ * Camino minimo en un g r a f o no pesado con BFS * /
3
http://oracleofbacon.org
70
CAP
ITULO 5. GRAFOS
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Prog. III
i f ( ! v i s i t a d o [w. p o s i c i o n ( ) ] ) {
v i s i t a d o [w. p o s i c i o n ( ) ] = true ;
d i s t a n c i a s [w. p o s i c i o n ( ) ] = nuevaDist ;
c o l a . poner (w) ;
}
a d y a c e n t e s . proximo ( ) ;
}
}
71
5.2. EL NUMERO BACON
53
54
55
56
}
57 }
Prog. III
/ * El a c t o r no e s t a r e l a c i o n a d o por ninguna
p e l i c u l a con Kevin Bacon * /
return I n t e g e r .MAX VALUE;
5.2.4.
1 c l a s s DFS {
2
private boolean v i s i t a d o s [ ] ;
3
private int d i s t a n c i a s [ ] ;
4
5
/ * Buscar e l v e r t i c e d e l a c t o r * /
6
private V e r t i c e <S t r i n g > b u s c a r A c t o r ( Grafo<S t r i n g > G,
String actor ) {
7
L i s t a G e n e r i c a <V e r t i c e <S t r i n g >> v e r t i c e s = G.
listaDeVertices () ;
8
v e r t i c e s . comenzar ( ) ;
9
while ( ! v e r t i c e s . f i n ( ) ) {
10
V e r t i c e <S t r i n g > v = v e r t i c e s . elemento ( ) .
verticeDestino () ;
11
i f ( v . dato ( ) . e q u a l s ( a c t o r ) )
12
return v ;
13
v e r t i c e s . proximo ( ) ;
14
}
15
return null ;
16
}
17
18
/ * Camino minimo en un g r a f o no pesado con DFS * /
19
public int numeroDeBacon ( Grafo<S t r i n g > G, S t r i n g
actor ) {
20
V e r t i c e <S t r i n g > i n i c i a l = b u s c a r A c t o r (G, Kevin
Bacon ) ;
21
V e r t i c e <S t r i n g > d e s t i n o = b u s c a r A c t o r (G, a c t o r ) ;
22
23
int N = G. l i s t a D e V e r t i c e s ( ) . tamanio ( ) ;
24
ColaGenerica <V e r t i c e <S t r i n g >> c = new ColaGenerica <
V e r t i c e <S t r i n g >>() ;
25
v i s i t a d o s [ ] = new boolean [N ] ;
26
d i s t a n c i a s [ ] = new int [N ] ;
72
CAP
ITULO 5. GRAFOS
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Prog. III
49
50
i f ( ! v i s i t a d o [w. p o s i c i o n ( ) ] )
51
numeroDeBaconDFS (w. v e r t i c e D e s t i n o ( ) , peso + 1 ) ;
52
53
a d y a c e n t e s . proximo ( ) ;
54
}
55
56
visitados [ v . posicion () ] = false ;
57
}
58 }
73
5.3.
Prog. III
5.3.1.
Hace falta recorrer el grafo de forma de obtener todos los caminos posibles
con una determinada longitud. La forma ms directa de resolverlo es un con
a
un DFS, probando todas las posibles combinaciones de aristas del grafo.
4
5
74
CAP
ITULO 5. GRAFOS
Prog. III
Para ello, por cada nodo del grafo hace falta iniciar un DFS, llevando la
lista de esquinas de la ciudad y el costo actual acumulado.
5.3.2.
1 c l a s s DFS {
2
boolean v i s i t a d o s [ ] ;
3
int d i s t a n c i a s [ ] ;
4
5
public L i s t a G e n e r i c a <L i s t a G e n e r i c a <S t r i n g >>
buscarCaminosDeCosto ( Grafo<S t r i n g > G, int c o s t o ) {
6
int N = G. l i s t a D e V e r t i c e s ( ) . tamanio ( ) ;
7
v i s i t a d o s [ ] = new boolean [N ] ;
8
d i s t a n c i a s [ ] = new int [N ] ;
9
L i s t a G e n e r i c a <L i s t a G e n e r i c a <S t r i n g >> r e s u l t a d o =
new L i s t a G e n e r i c a <L i s t a G e n e r i c a <S t r i n g >>() ;
10
11
for ( int i = 0 ; i < N; ++i ) {
12
visitados [ i ] = false ;
13
d i s t a n c i a s [ i ] = I n t e g e r .MAX VALUE;
14
}
15
16
for ( int i = 0 ; i < N; ++i ) {
17
L i s t a G e n e r i c a <S t r i n g > caminoActual = new
L i s t a G e n e r i c a <S t r i n g >() ;
18
V e r t i c e <S t r i n g > v = G. l i s t a D e V e r t i c e s ( ) . elemento (
i);
19
buscarCaminosDeCostoDFS ( v , r e s u l t a d o ,
caminoActual , c o s t o , 0 ) ;
20
}
21
22
return r e s u l t a d o ;
23
}
24
25
private void buscarCaminosDeCostoDFS ( V e r t i c e <S t r i n g >
v , L i s t a G e n e r i c a <L i s t a G e n e r i c a <S t r i n g >> r e s u l t a d o ,
L i s t a G e n e r i c a <S t r i n g > caminoActual , int c o s t o ,
int c o s t o A c t u a l ) {
26
v i s i t a d o s [ v . p o s i c i o n ( ) ] = true ;
27
caminoActual . a g r e g a r ( v . dato ( ) , caminoActual . tamanio
75
Prog. III
() ) ;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
i f ( c o s t o == c o s t o A c t u a l ) {
/ * Crear una c o p i a de l a l i s t a * /
L i s t a G e n e r i c a <S t r i n g > n u e v a L i s t a = new
L i s t a G e n e r i c a <S t r i n g >() ;
caminoActual . comenzar ( ) ;
while ( ! caminoActual . f i n ( ) ) {
n u e v a L i s t a . a g r e g a r ( caminoActual . elemento ( ) ,
n u e v a L i s t a . tamanio ( ) ) ;
caminoActual . proximo ( ) ;
}
resultado . agregar ( nuevaLista ) ;
}
L i s t a G e n e r i c a <A r i s t a <S t r i n g >> a d y a c e n t e s = v .
obtenerAdyacentes ( ) ;
a d y a c e n t e s . comenzar ( ) ;
while ( ! a d y a c e n t e s . f i n ( ) ) {
A r i s t a <S t r i n g > a = a d y a c e n t e s . elemento ( ) ;
V e r t i c e <S t r i n g > w = a . v e r t i c e D e s t i n o ( ) ;
i f ( ! v i s i t a d o s [w. p o s i c i o n ( ) ] ) {
buscarCaminosDeCostoDFS (w, r e s u l t a d o ,
caminoActual , c o s t o , c o s t o A c t u a l + a . peso ( ) )
;
}
48
49
50
a d y a c e n t e s . proximo ( ) ;
51
}
52
53
visitados [ v . posicion () ] = false ;
54
caminoActual . e l i m i n a r ( caminoActual . tamanio ( ) 1 ) ;
55
}
56 }
76
CAP
ITULO 5. GRAFOS
5.4.
Prog. III
Virus de Computadora
Un poderoso e inteligente virus de computadora infecta cualquier computadora en 1 minuto, logrando infectar toda la red de una empresa con cientos
de computadoras. Dado un grafo que representa las conexiones entre las
computadoras de la empresa, y una computadora ya infectada, escriba un
programa en Java que permita determinar el tiempo que demora el virus en
infectar el resto de las computadoras.
Asuma que todas las computadoras pueden ser infectadas, no todas las
computadoras tienen conexin directa entre s y un mismo virus puede ino
,
fectar un grupo de computadoras al mismo tiempo sin importar la cantidad.
Por ejemplo, si la computadora A se conecta con la B, y la B solo con la
C y D, el tiempo total desde la A ser de dos minutos: la A ya est infectada,
a
a
un minuto para la B, y un minuto para la C y D (ambas C y D al mismo
tiempo).
5.4.1.
Dibujo
5.4.2.
Caracter
sticas del grafo
5.4.3.
Prog. III
5.4.4.
1 c l a s s BFS {
2
public int c a l c u l a r T i e m p o I n f e c c i o n ( Grafo G, V e r t i c e
inicial ) {
3
int N = G. l i s t a D e V e r t i c e s ( ) . tamanio ( ) ;
4
Cola c = new Cola ( ) ;
5
boolean v i s i t a d o s [ ] = new boolean [N ] ;
6
int d i s t a n c i a s [ ] = new int [N ] ;
7
int maxDist = 0 ;
8
9
for ( int i = 0 ; i < N; ++i ) {
10
visitados [ i ] = false ;
11
d i s t a n c i a s [ i ] = I n t e g e r .MAX VALUE;
12
}
13
14
distancias [ i n i c i a l . posicion () ] = 0;
15
c o l a . poner ( i n i c i a l ) ;
16
17
while ( ! c o l a . e s V a c i a ( ) ) {
18
Vertice v = cola . sacar () ;
19
L i s t a G e n e r i c a <A r i s t a > a d y a c e n t e s ;
20
21
adyacentes = v . obtenerAdyacentes ( ) ;
22
a d y a c e n t e s . comenzar ( ) ;
23
while ( ! a d y a c e n t e s . f i n ( ) ) {
24
V e r t i c e w = a d y a c e n t e s . elemento ( ) .
verticeDestino () ;
25
int nuevaDist = d i s t a n c i a s [ v . p o s i c i o n ( ) ] + 1 ;
26
78
CAP
ITULO 5. GRAFOS
Prog. III
27
i f ( ! v i s i t a d o [w. p o s i c i o n ( ) ] ) {
28
v i s i t a d o [w. p o s i c i o n ( ) ] = true ;
29
d i s t a n c i a s [w. p o s i c i o n ( ) ] = nuevaDist ;
30
i f ( nuevaDist > maxDist )
31
maxDist = nuevaDist ;
32
c o l a . poner (w) ;
33
}
34
a d y a c e n t e s . proximo ( ) ;
35
}
36
}
37
38
return maxDist ;
39
}
40 }
79
5.5. CIRCUITOS ELECTRONICOS
5.5.
Prog. III
Circuitos Electrnicos
o
o
n
que le llegan a una compuerta NAND lo hacen a diferente tiempo, y la salida
de la compuerta tardar en estabilizarse. Asuma que tiempo que demoran las
a
seales en viajar por los cables es cero, y el tiempo que demoran las seales
n
n
en atravezar una compuerta es el mismo para todas.
Se tiene un grafo que representa el circuito electrnico, y una unica eno
5.5.1.
Dibujo
5.5.2.
Caracter
sticas del grafo
CAP
ITULO 5. GRAFOS
5.5.3.
Prog. III
Hay una carrera cuando una seal le llega a una compuerta ms rpido
n
a a
por una de las entradas que por las otras.
Por ejemplo, en el dibujo anterior estn las compuertas 1 y 2, una entrada
a
por donde se disparan las seales, y una salida, por donde queda el resultado
n
de las compuertas. Las seales que le llegan a la compuerta 1 son todas al
n
mismo momento de tiempo, pero las seales que le llegan a la compuerta 2
n
lo hacen a diferente tiempo, porque una de las entradas es la salida de la
compuerta 1.
La idea del ejercicio es hacer el seguimiento de los diferentes caminos
que pueden tomar la seal. No es necesario hacer una lista de todos, sino
n
encontrar el caso de la primer carrea.
Una forma de ver la solucin es simular el paso del tiempo en el circuito,
o
haciendo el mismo recorrido que las seales a lo largo del tiempo. Eso se
n
puede hacer de dos formas: BFS o DFS.
En el caso del DFS, por cada nodo que se visita se va incrementando en
1 un contador a medida que se llama a la recursin, este valor se lo almacena
o
en una tabla, y si cuando se vuelve a visitar un nodo por segunda vez el valor
es diferente al primero, hay una carrera.
En el BFS es similar, pero hace falta diferenciar correctamente los nodos
visitados de los que no lo estn. Tambien, es necesario mantener una tabla;
a
si el nodo no fue visitado actualizr el valor como el valor del padre + 1, y si
el nodo ya fue visitado vericar que el valor es el mismo que el del padre +
1. Esto se hace dentro del while que recorre adyacentes.
En ambos casos, el contador sirve para ver en qu instante de tiempo le
e
estn llegando las seales a la compuerta. Si por un lado le llega un valor
a
n
diferente al que le llega por el otro, quiere decir que le llegan a diferente
tiempo y entonces hay una carrera.
5.5.4.
5.5. CIRCUITOS ELECTRONICOS
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Prog. III
24
25
26
27
28
29
30
31
i f ( ! v i s i t a d o s [w. p o s i c i o n ( ) ] ) {
v i s i t a d o s [w. p o s i c i o n ( ) ] = true ;
d i s t a n c i a s [w. p o s i c i o n ( ) ] = n u e v a D i s t a n c i a ;
c o l a . poner (w) ;
} else {
i f ( d i s t a n c i a s [w. p o s i c i o n ( ) ] !=
nuevaDistancia )
return true ; / * Hay c a r r e r a * /
}
a d y a c e n t e s . proximo ( ) ;
32
33
34
35
}
36
}
37
return f a l s e ;
38
}
39 }
5.5.5.
1 c l a s s DFS {
2
boolean v i s i t a d o s [ ] ;
82
CAP
ITULO 5. GRAFOS
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Prog. III
int d i s t a n c i a s [ ] ;
public boolean hayCarrera ( Grafo<I n t e g e r > G, V e r t i c e <
Integer> i n i c i a l ) {
int N = G. l i s t a D e V e r t i c e s ( ) . tamanio ( ) ;
v i s i t a d o s [ ] = new boolean [N ] ;
d i s t a n c i a s [ ] = new int [N ] ;
for ( int i = 0 ; i < N; ++i ) {
visitados [ i ] = false ;
d i s t a n c i a s [ i ] = I n t e g e r .MAX VALUE;
}
return hayCarreraDFS ( i n i c i a l , 0 ) ;
}
private boolean hayCarreraDFS ( V e r t i c e <I n t e g e r > v , int
tiempo ) {
v i s i t a d o s [ v . p o s i c i o n ( ) ] = true ;
i f ( d i s t a n c i a s [ v . p o s i c i o n ( ) ] != I n t e g e r .MAX VALUE)
{
i f ( d i s t a n c i a s [ v . p o s i c i o n ( ) ] != tiempo ) {
visitados [ v . posicion () ] = false ;
return true ;
}
} else {
d i s t a n c i a s [ v . p o s i c i o n ( ) ] = tiempo ;
}
L i s t a G e n e r i c a <V e r t i c e <I n t e g e r >> a d y a c e n t e s = v .
obtenerAdyacentes ( ) ;
a d y a c e n t e s . comenzar ( ) ;
while ( ! a d y a c e n t e s . f i n ( ) ) {
V e r t i c e <I n t e g e r > w = a d y a c e n t e s . elemento ( ) .
verticeDestino () ;
i f ( ! v i s i t a d o s [w. p o s i c i o n ( ) ] && hayCarreraDFS (w,
tiempo + 1 ) )
visitados [ v . posicion () ] = false ;
return true ;
}
83
5.5. CIRCUITOS ELECTRONICOS
38
a d y a c e n t e s . proximo ( ) ;
39
}
40
41
visitados [ v . posicion () ] = false ;
42
return f a l s e ;
43
}
44 }
84
Prog. III
CAP
ITULO 5. GRAFOS
5.6.
Prog. III
Viajante de Encuestas
5.6.1.
5.6.2.
Implementacin Java
o
1 class ViajanteDeEncuestas {
2
int N;
3
boolean [ ] v i s i t a d o s ;
4
L i s t a G e n e r i c a <S t r i n g > mejorCamino ;
6
Categorizar problemas como P, NP, NPC, NPH es un tema que se encuentra fuera del
alcance de este curso.
85
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Prog. III
}
void calcularCaminoMinimoDFS ( V e r t i c e <S t r i n g > V,
L i s t a G e n e r i c a <S t r i n g > caminoActual , int c a n t V i s i t ,
int c o s t o A c t u a l ) {
v i s i t a d o s [V. p o s i c i o n ( ) ] = true ;
caminoActual . a g r e g a r (V. dato ( ) , caminoActual . tamanio
() ) ;
i f ( c a n t V i s i t == N && c o s t o A c t u a l <
mejorCaminoCosto )
{
/ * Copiar l a l i s t a * /
L i s t a G e n e r i c a <S t r i n g > n u e v a L i s t a = new
L i s t a E n l a z a d a G e n e r i c a <S t r i n g >() ;
caminoActual . comenzar ( ) ;
while ( ! caminoActual . f i n ( ) ) {
n u e v a L i s t a . a g r e g a r ( n uev aL ist a , n u e v a L i s t a .
tamanio ( ) ) ;
caminoActual . proximo ( ) ;
}
/ * A c t u a l i z a r e l camino minimo * /
mejorCamino = n u e v a L i s t a ;
mejorCaminoCosto = c o s t o A c t u a l ;
86
CAP
ITULO 5. GRAFOS
37
38
39
40
41
42
43
44
45
46
47
Prog. III
}
else
{
/ * S e g u i r DFS en l o s a d y a c e n t e s * /
L i s t a G e n e r i c a <S t r i n g > a d y a c e n t e s = V.
obtenerAdyacentes ( ) ;
a d y a c e n t e s . comenzar ( ) ;
while ( ! a d y a c e n t e s . f i n ( ) ) {
A r i s t a <S t r i n g > A = a d y a c e n t e s . elemento ( ) ;
V e r t i c e <S t r i n g > W = A. v e r t i c e D e s t i n o ( ) ;
i f ( ! v i s i t a d o s [W. p o s i c i o n ( ) ] ) {
calcularCaminoMinimoDFS (W, c a n t V i s i t + 1 ,
c o s t o A c t u a l + A. peso ( ) ) ;
}
a d y a c e n t e s . proximo ( ) ;
}
}
48
49
50
51
52
53
caminoActual . e l i m i n a r ( caminoActual . tamanio ( ) 1 ) ;
54
v i s i t a d o s [V. p o s i c i o n ( ) ] = f a l s e ;
55
}
56 }
87