Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Problema P1
Problema P1
del Proyecto 1
Rozo Fajardo, Nicolas Ortiz Gomez, Andres
n.rozo@uniandes.edu.co a.ortizg@uniandes.edu.co
Tapias Guzman, David Santiago
ds.tapias@uniandes.edu.co
Septiembre de 2023
1 Estrategia de Diseño
Antes de crear la ecuación de recurrencia que modela y resuelve el problema, nuestro proceso de diseño comenzó
con una observación simple pero poderosa sobre el patrón implı́cito en las configuraciones finales. En primer lugar,
notamos que en cualquier configuración final con i rocas, j ranas y k movimientos, existen dos escenarios
posibles. Uno donde la rana j se encuentra en la piedra i (esto ocurre si la distancia entre la rana j y la piedra
i es menor o igual a k, y otro donde la rana j no se encuentra en la piedra i. Por lo tanto, la cantidad total
de configuraciones finales es la suma de estos dos casos. Además, reconocimos que, debido a la naturaleza y la
lógica inherente del problema, era necesario establecer casos base para i=0, j=0, y k=0.Con esta perspicacia en
mente, diseñamos la relación de recurrencia c(i, j, k), la cual devuelve el número de configuraciones finales válidas
que se obtienen al ubicar j ranas en las primeras i piedras usando k movimientos. A continuación, se presenta una
descripción detallada de cada uno de los casos de la relación de recurrencia, junto con su posterior formalización
matemática.
• Caso Base 1: Si el número de ranas es mayor que el número de piedras, no se puede formar ninguna
configuración válida, sin importar la cantidad de movimientos disponibles. Por lo tanto, la recurrencia retorna
0.
Para los siguientes casos, se debe cumplir que la cantidad de ranas es menor o igual que la cantidad de piedras.
• Caso Base 2: Si el número de piedras es 0, tampoco se puede formar ninguna configuración válida, por lo
cual la recurrencia retorna 0.
Para los siguientes casos, se debe cumplir que la cantidad de piedras es mayor a 0.
• Caso Base 3: Si el número de ranas es mayor que 0 y el número de movimientos es 0, solo se puede formar
una configuración válida si las primeras j ranas se encuentran en las primeras i piedras. En la relación de
recurrencia, esta verificación se realiza con el enunciado v(i, j), el cual retorna 1 si las primeras j ranas se
encuentran en las primeras i piedras o 0 de lo contrario. A nivel de implementación, esta verificación se realiza
con la función verify.
• Caso Base 4: Si el número de ranas es 0 y el número de movimientos es 0, solo se puede formar una
configuración válida (solo hay una forma de no elegir ranas), por lo cual la recurrencia retorna 1.
Para los siguientes casos, se debe cumplir que el número de movimientos es mayor a 0.
• Caso Base 5: Si la cantidad de ranas es igual a 0, la recurrencia retorna 0, ya que no existen formas de no
seleccionar ranas usando k movimientos.
• Caso Recursivo 1: Si el número de ranas es igual a 1 y la distancia entre la rana 1 y la piedra i (rep-
resentada mediante el enunciado d(i, j) en la ecuación de recurrencia y mediante la función distance en la
implementación) es igual al número de movimientos disponibles, entonces existen 1 + c(i − 1, j, k) configura-
ciones finales posibles. Esto es, una configuración en la que la rana 1 llega a la piedra 1 más la cantidad de
configuraciones finales que se pueden lograr con 1 rana y k movimientos en i-1 piedras.
• Caso Recursivo 2: Si el número de ranas es igual a 1 y la distancia entre la rana 1 y la piedra i es diferente
al número de movimientos disponibles, entonces la rana 1 no puede llegar a la piedra i y la cantidad de
configuraciones finales está dada por c(i, j, k), es decir, la cantidad de configuraciones finales que se pueden
lograr al ubicar 1 rana con k movimientos en i-1 piedras.
1
• Caso Recursivo 3: Si el número de ranas es mayor a 1 y la distancia entre la rana j y la piedra i es menor o
igual a la cantidad de movimientos disponibles, entonces se suman la cantidad de configuraciones que se logran
cuando la rana j no está en la piedra i con la cantidad de configuraciones finales que se logran después de
ubicar a la rana j en la piedra i. Esto es c(i − 1, j, k) + c(i − 1, j − 1, k − d).
• Caso Recursivo 4: Si el número de ranas es mayor a 1 y la distancia entre la rana j y la piedra i es mayor
que la cantidad de movimientos disponibles, entonces la rana j no puede llegar a la piedra i y, por ende, se
ignora ese caso. Esto es c(i − 1, j, k).
0 j>i
0 (j ≤ i) ∧ (i = 0)
0 (j ≤ i) ∧ (i > 0) ∧ (j = 0) ∧ (k > 0)
1 (j ≤ i) ∧ (i > 0) ∧ (j = 0) ∧ (k = 0)
C(i, j, k) = V (i, j) (j ≤ i) ∧ (i > 0) ∧ (j > 0) ∧ (k = 0) (1)
1 + C(i − 1, j, k) (j ≤ i) ∧ (i > 0) ∧ (j = 1) ∧ (k > 0 ∧ k = d)
C(i − 1, j, k) (j ≤ i) ∧ (i > 0) ∧ (j = 1) ∧ (k > 0 ∧ k ̸= d)
C(i − 1, j, k) + C(i − 1, j − 1, k − d) (j ≤ i) ∧ (i > 0) ∧ (j > 1) ∧ (k > 0 ∧ k ≥ d)
C(i − 1, j, k) (j ≤ i) ∧ (i > 0) ∧ (j > 1) ∧ (k > 0 ∧ k < d)
Finalmente, es necesario destacar que el algoritmo propuesto soluciona a la perfección el problema debido a que
aborda de manera exhaustiva el problema planteado al considerar todas las posibles subconfiguraciones para llegar
a la respuesta final. Sin embargo, su complejidad temporal se reduce significativamente, pasando de exponencial (si
se utiliza únicamente la recursión) a polinomial gracias a la aplicación del enfoque de programación dinámica.
makeArray O(n).
Esta función tiene un solo bucle for que itera sobre cada carácter en la cadena de entrada. La complejidad temporal
de convertir una cadena en una matriz de caracteres es O(n), donde n es la longitud de la cadena.
makeMap O(n)
La función recorre los elementos del arreglo initConfig.El bucle inserta un par clave-valor en infoMap e incrementa
la variable cont si el carácter actual es equivalente a R. El tiempo promedio requerido para una operación de inserción
en un mapa hash es constante O(1). Como resultado, la complejidad temporal del bucle, incluida la inserción en
HashMap se puede expresar como O(n) de forma asintotica.
2
verify O(1)
En esta función las operaciones incluyen verificar si la clave j existe en infoMap utilizando el método containsKey(),
recuperar el valor asociado con la clave j utilizando el método get(), y comparar el valor recuperado con i - 1.
distance O(1)
El fragmento de código tiene una complejidad temporal constante de O(1) porque realiza un número constante de
operaciones independientemente del tamaño de la entrada. Las operaciones incluyen verificar si la clave j existe en
el infoMap utilizando el método containsKey(), recuperar el valor asociado con la clave j utilizando el método
get(), y realizar una operación de resta y valor absoluto. Estas operaciones no dependen del tamaño del mapa ni
de los valores de i y j.
countFrogs
El analisis de complejidad de tiempo para etsa función se va a detallar en 3 secciónes:
1. Inicialización y Procesamiento de la Entrada:
• Crear la matriz de caracteres config a partir de initConfigString toma un tiempo de O(n), donde n
es la longitud de la cadena de entrada.
• Crear el mapa infoDict utilizando la función makeMap también toma un tiempo de O(n) ya que procesa
la matriz config.
2. Bucles Anidados Triples:
• El trabajo computacional principal ocurre dentro de los bucles anidados triples:
– El bucle más externo itera desde k = 0 hasta k = movements, lo que resulta en movements + 1
iteraciones.
– El bucle intermedio itera desde i = 0 hasta i = rocks, lo que resulta en rocks + 1 iteraciones.
– El bucle más interno itera desde j = 0 hasta j = f rogs, lo que resulta en f rogs + 1 iteraciones.
3. Operaciones Dentro de los Bucles Anidados:
• Las operaciones dentro de los bucles anidados consisten en declaraciones condicionales y operaciones
aritméticas. Analicemos la complejidad de estas operaciones:
– La condición if (j > i) es una comparación simple y tiene una complejidad temporal de O(1).
– Las funciones verify y distance se llaman dentro de los bucles. Estas funciones se han analizado
previamente:
∗ La función verify tiene una complejidad temporal de O(1).
∗ La función distance también tiene una complejidad temporal de O(1).
– Las operaciones aritméticas, como la suma y la resta, también son operaciones de tiempo constante
y tienen una complejidad de O(1).
4. Complejidad Espacial & Temporal:
• Finalmente, la función tiene una complejidad temporal de O(movements ∗ rocks ∗ f rogs) segun su com-
portamiento asintotico. Por otro lado, la complejidad en espacio tambien es de orden O(movements ∗
rocks ∗ f rogs) ya que se usan matrices 2D (rocks * frogs) y tenemos k matrices de este tipo donde k es
el numero de movimientos.
3
3.2 Escenario 2: Todas las ranas deben ir en la misma dirección
• Nuevos Retos: En este caso, debido a que todas las ranas se deben mover en la misma dirección, serı́a
necesario controlar la dirección de movimiento mediante un parámetro, a la vez que se deberı́a restringir la
forma en la cual se calculan las distancias, ya que no siempre se podrá realizar el movimiento desde la dirección
especificada.
• Cambios Necesarios: Un cambio que se podrı́a aplicar sobre la solución actual serı́a el de usar dos matrices
con las mismas caracterı́sticas que la actual, y en una contar las configuraciones que se pueden lograr moviendo
todas las ranas a la derecha, y en la otra contar lo mismo pero restringiendo el movimiento hacia la izquierda.
Para esto serı́a necesario que la función de distancia tome en cuenta la dirección y, el resultado final, se
obtendrı́a sumando las entradas [p][r][m] de ambas matrices.