Está en la página 1de 5

Solucionario de 3er Cuscontest PROBLEMA A (HORA DE COMER) Listo para algo de aritmtica ingeniosa?

, empezaremos por notar que los puntos de partida de las orugas coinciden con la primera hoja de la rama. Seguidamente una comida le sigue en cada distancia que es divisible por la distancia que recorre la oruga y la distancia en donde se encuentra cada hoja, estamos buscando mltiplos comunes de D (descanso) y H (hoja) por lo tanto tenemos la formula para calcular el MCM mnimo comn mltiplo o (LCM) Least Common Multiple.
def lcm(Descanso, Hoja): return Descanso / gcd(Descanso, Hoja) * Hoja

el gcd es el MCD (mximo comn divisor) que puede ser calculado fcilmente con esta definicin recursiva.
def gcd(D, H): if (H == 0): return D return gcd(H, D % H)

Luego determinamos cuantas veces el mnimo comn mltiplo encaja en la longitud de la rama, agregando 1 por la hoja inicial, de manera que el nmero total de hojas comidas es calculado como sigue:
def hojas_comidas(Rama, Descanso , Hoja): return Rama / lcm(Descanso, Hoja) + 1

Tambin se tiene un enfoque de fuerza bruta, dado que la rama ms grande es a lo ms 1 milln de unidades de longitud, no tomar mucho en ejecutar una simulacin. El siguiente pseudocdigo muestra como podemos tomar ventaja de las posiciones de la oruga cada D (distancia y luego descanso) unidades y en cada estacin verificamos si es divisible con la distancia de las hojas, de esa manera verificamos si descanso o no en una posicin donde haba una hoja y de esa forma saber si comi o no la hoja correspondiente a esa posicin.
def simulacion_comerhojas(Rama, Descanso, Hoja): comida = 0 pos = 0 while (pos <= Rama): if (pos%Hoja == 0): comida = comida+1 pos = pos+Descanso return comida

PROBLEMA B PLEGADO DE PAPEL Creo recordar al Seor Wizard demostrando que no puedes doblar un papel ms de 8 veces. En cualquier caso, este problema es resuelto con un simple algoritmo de fuerza bruta. Dado que doblar un papel en una direccin es independiente de doblarlo en otra direccin, tiene sentido considerar ambas direcciones (ancho y largo) independientemente. Tambin debido a que puedes rotar el papel 90 grados, deberas intentar encajar cada dimensin del papel en cada dimensin de la caja (sea primero ancho largo con ancho-largo y luego con largo-ancho con ancho largo), si el nmero de pliegues requeridos para cualquiera de las direcciones excede 8 entonces esa direccin es invalida, si cualquiera de las direcciones es invalida escribir -1, caso contrario retornar el mnimo nmero de los validos, sea el mnimo encontrado ya sea teniendo al papel (ancho largo) con la hoja (ancho largo) o al papel rotado 90 grados y aplicado el mismo algoritmo (largo ancho) con la hoja (ancho largo).

En la imagen vemos su solucin equivalente pero en este caso duplicamos la longitud ya sea vertical u horizontal de la caja y cuando sea mayor o igual al papel tanto en ancho como en largo (sea ya contiene a la hoja) ya hemos

encontrado cuantos plegados necesitbamos, esto se hace tanto (anchoancho largo-largo o ancho-largo con largo-ancho) y luego elegir con cual de los dos hicimos menos pliegues, en el ejemplo vemos que con la primera haramos menos pliegues es decir 2.

V H , V / 2

P P P

r o r o r o

f u f u f u

n n n

d d d

id id

a a

d d

0
H / 2 , V

1 V H / 2 , V / 2
H , V / 4

H id a

/ 4 , d 2

Se puede realizar tambin un algoritmo de bsqueda completa, en este caso una bsqueda recursiva ya que podemos doblar a lo ms 8 veces, nuestra bsqueda terminara cuando alcance una profundidad de 8 (complejidad 2^8 = 255 combinaciones), es decir en cada recorrido que se haga, elegiremos o bien doblar el ancho o el largo y verificaremos en cada nodo(el circulo amarillo) si ya se tiene la situacin en la que el ancho y el largo ya es menor o igual que la caja contenedora si es as retornar su profundidad actual caso contrario seguir buscando hasta a lo ms una profundidad de 8, si en la profundidad 8 seguimos sin conseguir que tanto ancho como largo sea menor que las dimensiones de la caja entonces retornamos un valor grande constante, para que al final comparemos y si por todos los caminos nos devuelve ese valor grande significa que por ninguna combinacin (ancholargo o largo-ancho de plegados) con una profundidad hasta de 8 se pudo conseguir que las dimensiones del papel sean menores o iguales a las dimensiones de la caja entonces imprimimos -1. Se adjunta tambin un caso curioso en el cual la recursin se puede reducir a una tabla (matriz) ya que hay nodos que contendrn valores similares (flecha roja) entonces ya no ser necesario recorrer cada nodo sino una matriz de 8x8, la solucin se deja a la imaginacin del concursante (eso es conocido como DP, programacin dinmica y un ejemplo comn de esto es el LCS (longest common subsequence) o subsecuencia comn ms larga que

... ... ... .... .. . ..

usualmente lo ensean de frente con tabla sin explicarlo que todo empieza con la recursin, al menos as fue mi historia xD!).

PROBLEMA C ESPIRAL Dado que este problema no tiene dificultades para ser entendido sino mas bien la dificultad esta en simular el recorrido, pasaremos a explicar la simulacin sin mas. Este problema puede ser resuelto de varias formas, en sta ocasin la resolveremos con un modulo recursivo similar al de recorrer un laberinto. El modulo para hacer el recorrido en la matriz de dimensiones A[n][n], donde n es el tamao de la matriz, es el siguiente:
void backtrack(int x,int y,int dir) { if((0<=x)&&(x<n)&&(0<=y)&&(y<n)) { if(A[x][y]==-1) { A[x][y]=cont++; if(dir==0) {backtrack(x,y+1,dir); if(dir==1) {backtrack(x+1,y,dir); if(dir==2) {backtrack(x,y-1,dir); if(dir==3) {backtrack(x-1,y,dir); backtrack(x,y+1,dir%4); } } }

dir++;} dir++;} dir++;} dir++;}

Podemos observar que este modulo es similar a la de recorrer un laberinto con la diferencia que este modulo tiene un parmetro de mas, que es dir, cuya funcin es de dar la direccin respectiva para el recorrido de nuestra espiral, al inicio de este modulo preguntamos si los valores x, y no estn saliendo de los parmetros de la matriz A, si fuese as el modulo retorna a la llamada anterior para cambiar de direccin, dado que la matriz inicialmente esta llena de -1 para llevar el control de si todava no hemos visitado ese casillero , es decir si A[x][y] es igual a -1 entonces ese casillero no se visito, y podemos colocar el contador en dicho casillero cont++ , luego de esto cada dir nos permitir saber hacia donde debemos movernos, dir++ se utiliza para que una vez que hayamos llegado a un extremo de la matriz cambie de direccin y la ultima llamada recursiva backtrack(x,y+1,dir%4) esta modulo 4 para regresar a la primera direccin y pueda repetirse el proceso descrito.