20060804-Solucion

10
MISIONEROS Y CANÍBALES Autor... Juan Carlos San Martin Bravo Id........ 01626604 Fecha.. 18 de noviembre de 2002 Email... [email protected] Web.... http://www2.netexplora.com/atila/ing.htm ¿Para qué sirve este programa? ¿Cómo usar este programa? ¿Cómo funciona este programa? Limitaciones. ¿PARA QUÉ SIRVE ESTE PROGRAMA? ¿Has oido este acertijo?: Tres misioneros y tres canibales llegan a la orilla de un rio y hallan un bote con capacidad para dos personas. Deben cruzar al otro lado usando el bote, pero cada vez que en una orilla hay mas canibales que misioneros, los ultimos son devorados por los antropofagos. Halla la manera de cruzarlos a todos sanos y salvos. Considera que el bote no se devuelve solo y que si hay mas canibales que misioneros en el bote (si caben solo 2 no se aplica) se comen a estos ultimos. Mi programa puede resolver este acertijo facilmente. ¿Que es poca cosa? A ver, ¿puedes determinar como cruzar 500000 misioneros y 499999 canibales en una barca de 2 personas? ¿O determinar si tiene solucion querer cruzar 33 misioneros y 33 canibales en un bote para 3 personas? Bueno, mi programa puede echarte una mano.

description

solucion

Transcript of 20060804-Solucion

MISIONEROS Y CANBALES

Autor... Juan Carlos San Martin Bravo

Id........ 01626604

Fecha.. 18 de noviembre de 2002

Email... [email protected]

Web.... http://www2.netexplora.com/atila/ing.htmPara qu sirve este programa?

Cmo usar este programa?

Cmo funciona este programa?

Limitaciones.

PARA QU SIRVE ESTE PROGRAMA?

Has oido este acertijo?: Tres misioneros y tres canibales llegan a la orilla de un rio y hallan un bote con capacidad para dos personas. Deben cruzar al otro lado usando el bote, pero cada vez que en una orilla hay mas canibales que misioneros, los ultimos son devorados por los antropofagos. Halla la manera de cruzarlos a todos sanos y salvos.

Considera que el bote no se devuelve solo y que si hay mas canibales que misioneros en el bote (si caben solo 2 no se aplica) se comen a estos ultimos.

Mi programa puede resolver este acertijo facilmente. Que es poca cosa? A ver, puedes determinar como cruzar 500000 misioneros y 499999 canibales en una barca de 2 personas? O determinar si tiene solucion querer cruzar 33 misioneros y 33 canibales en un bote para 3 personas? Bueno, mi programa puede echarte una mano.

En la siguiente pgina hay un juego sobre cmo resolver el acertijo de los 3 misioneros, de los 3 canbales y de la barca con capacidad para 2 personas:

http://galeon.hispavista.com/amigosharry/java/flash/juego2.htmTen en cuenta que este programa no es un juego: solo te dice cmo resolver un problema, si es que tiene solucn.

CMO USAR ESTE PROGRAMA?

T tienes un problema. Han llegado M>0 misioneros (incluyndote) y C>0 canbales a la orilla sur del ro Congo, y frente a ustedes hay una barca con capacidad para llevar B>1 personas. Deben cruzar todos a la orilla norte, pero cmo hacerlo con las limitaciones que ya sabes?: no pueden haber menos misoneros que canbales en ninguna orilla ni tampoco dentro de bote.

Afortunadamente, aunque ests en medio de una jungla impentrable y virgen, en tu morral tienes un notebook con un celular satelital, enchufas el celular al computador y a travs de ste te conectas a internet. Buscas en google y oh, caracoles!, llegas a mi pgina web y te encuentras con este sper programa, que a t no te costar nada usar...

Lo ejecutas, y luego de la bienvenida te pregunta cuntos misioneros son ustedes, cuntos antropfagos los acompaan y la capacidad del bote. Luego te pregunta si deseas un anlisis silencioso o detallado. En el detallado el programa te informa todos los pasos que sigue para llegar a una solucin; en el modo silencioso trabaja sin mostrar informacin por pantalla.

Personalmente te aconsejo el modo silencioso: es ms rpido y no tienes que estar apretando INTRO a cada rato...

Bueno, das esos datos, apretas INTRO y oh, cielos!!, en menos de lo que te tiras un peo tienes la solucin o el informe de que no se encontr.

Si el programa hall la forma de cruzarlos sanos y salvos a todos ustedes, almacenar el algoritmo en un archivo de texto SOLUCION161119811600.txt El nmero debe interpretarse como 16-11-1981 a las 16:00.

Existen algunas condiciones para los parmetros de partida:

M ( [ 0 , ( ]

C ( [ 0 , ( ]

B ( [ 2 , ( ]

M y C no pueden ser ambos nulos.

M >= C

Como yo no soy perfecto (qu humilde, qu se cree este %&$#?), mi programa tiene limitaciones. Entrate de ellas en la seccin correspondiente.

CMO FUNCIONA ESTE PROGRAMA?, CMO LO HICE?

Dados los parmetros M, C y B que cumplan las condiciones ms arriba sealadas, el algoritmo a seguir se detallar a continuacin:

1.- Elaborar lista de combinaciones.

Lo primero es considerar cuntas combinaciones existen para el uso del bote dada una capacidad B. Matemticamente el nmero de combinaciones est dada por la funcin Atilanacci, nombre recibido en honor mo y a que en un primer momento me pareci semejante a la sucesin de Fibonacci:

Atilanacci (B) = (n (n+3))

2

As, supongamos que B=3. Cuntas combinaciones existen para usar un bote con tal capacidad?

Atilanacci (3) = 0.5 (3 (6)) = 9

O sea, hay 9 combinaciones totales. Y cules son? Las almacenaremos en un arreglo de enteros, a saber:

arreglo302112032011021001

el que leemos como: 3 misioneros, 0 canbal; 2m 1c; 1m 2c; etc...

Este es un arreglo de las combinaciones brutas, que no repara en el hecho de que la combinacin 1m 2c es inviable puesto que los canbales dentro el bote se comeran a los misioneros.

Pero no hay problema. Ahora creamos una lista ligada de combinaciones, cuya estructura es la siguiente:

struct l //LISTA: doblemente ligada de combinaciones tiles de m y c en el bote

{

int m; //indica cuntos misioneros hay en el bote

int c; //dem con los canbales

int id; //identidad de la jugada (de 0 a n...)

struct l *izq;

struct l *der;

};

typedef struct l LISTA;

Es una lista doblemente ligada que contiene las combinaciones tiles de misoneros y canbales transportados en la barcaza. Esas combinaciones las sacamos del arreglo menciondo anteriormente.

As, para el caso de que B=3, tendramos una lista de esta guisa:

m32021010

c01301201

id01234567

Por supuesto, imagnensela como una lista doblemente ligada. Adems, conservaremos punteros al primer elemento (el de id=0) y al ltimo. Por qu? Ya se ver.

2.- Mientras queden combinaciones tiles, crear jugada maestra.

A qu denomino jugadas maestras? Al conjunto de las primeras jugadas que se pueden realizar dada una situacin inicial. En el caso de B=3, las jugadas maestras que pueden hacerse son 8, una por cada combinacin.

La jugada maestra tiene un puntero a la raz de un rbol n-ario de jugadas que potencialmente podran generarse a partir de ella. Las jugadas maestras estn representadas en una lista simplemente ligada con un puntero a su primer elemento.

3.- Anlisis de la jugada maestra.

Como ya se dijo, la jugada maestra apunta a la raz de un potencial rbol n-ario de jugadas descendientes de ella. Pero primero aclaremos algo:

TDA para el manejo de las jugadas.

Ser un rbol n-ario de nodos, cada uno de los cuales representar una jugada cualquiera.

Clasificacin de las Jugadas.

Una jugada cualquiera puede ser INFRTIL, por ejemplo si deja una cantidad negativa de personas en alguna orilla; REPETIDA si tiene el mismo sentido, la misma combinacin y los mismos resultados que otra (por ejemplo, viajar ambas hacia el norte con 1 m y 0 c y dejar en la orilla norte 3m,1c y en la sur 4m,3c); ANTROPOFGICA si deja menos misioneros que canbales en alguna orilla; TERMINAL, si es aquella en que en la orilla sur quedan 0 misioneros y 0 canbales; o FRTIL, que es aquella jugada que no tiene la calidad de ninguna de las anteriores.

Criterio para la generacin de jugadas.

Solo podrn generarse jugadas a partir de jugadas frtiles, y stas nuevas jugadas hijas sern opuestas en sentido y no inversas en combinacin a su madre.

Por ejemplo, si la jugada madre apunta a la combinacin de id=1 (2m,1c) y tiene sentido DERECHO (va hacia el Norte), las hijas podrn apuntar a cualquier combinacin excepto a la de id=1, y tendrn sentido REVES.

Eleccin del Algoritmo ms Reducido.

En caso de tener solucin el problema, y para hallar la secuencia de pasos ms reducidas, a la hora de generar jugadas de sentido DERECHO (las que llevan personas hacia el norte), primero consideraremos las combinaciones que ms gente lleven (para eso es el puntero al primer elelmento de la lista de combinaciones). En caso de generar jugadas de sentido REVES (cuyo propsito es devolver el bote a la orilla sur) se considerarn las combinaciones que menos gente trasladen.

En el caso B=3, la primera opcin para crear jugadas con sentido DERECHO sera llevar 3m y 0c; al contrario, si de crear jugadas con sentido REVES se trata, la primera opcin sera llevar 0m y 1c.

Este permite elegir el camino ms corto, reduciendo uso de RAM y de CPU a tener rboles n-arios ms reducidos y con menor cantidad de elementos.

Hechas ests aclaraciones, veamos el algoritmo de anlisis de un rbol de jugadas:

NODO* Analisis (NODO* raiz, LISTA *derecho, LISTA *reves)

{

p=raz; //p apunta a la jugada actual...

Mientras (p no sea TERMINAL)

{

Si (p es FRTIL)

{

Si (p no tiene hijos)

{

Darle jugada hija[0], opuesta y no inversa.

p=hijo[0] //probar con la jugadahija...

}

sino

{

Si (quedan combinaciones opuestas y no inversas)

{

Darle hijo[sig]

p es hijo[sig];

}

sino //si ya no quedan hijos para evaluar, es porque el pap es infrtil

{

eliminar descendencia de p

p es INFRTIL;

}

}

}

sino // si la jugada p no es FERTIL (REPETIDA,INFERTIL, etc...)

{

Si (p es la raz) // rbol n-ario abortado...

return NULL;

sino

{

p es INFERTIL;

p=p->papa; // probaremos con el papa nuevamente

}

}

}

//en caso de que hubiese sido hallada la jugada terminal, se rompe el while y...

return p;

}

Bsicamente ese es el razonamiento (algoritmo o secuencia de pasos) que pens para solucionar el problema. Pero cuando cre haber terminado este programa, me top con otro grave:

Bsqueda de Jugadas Repetidas.

Problema grave? Por qu, si es cosa de recorrer recursivamente el rbol n-ario e ir comparando las jugadas?

Eso fue lo primero que hice. La verdad es que funciona relativamente bien, pero, en especial a la hora de analizar casos sin solucin, deja harto que desear: consume mucho tiempo. Recorrer un rbol n-ario por cada jugada que se le aade es muy ineficiente; adems, el rbol va creciendo, por lo que por cada jugada aadida se demora ms y ms en recorrerlo. Si tenemos un rbol n-ario de m jugadas, recorrerlo todo tendr una eficiencia O (n^m). Un asco... el consumo de tiempo de CPU es repugnante.

Y cmo acelerar la bsqueda de jugadas repetidas? Primero, reducir el espectro de jugadas que han de ser recorridas, comparando la jugada que se evala solo con otras similares, no con todas. Una jugada es similar a otra cualquiera si lleva la misma cantidad de gente (apunta a la misma combinacin) y adems poseen el mismo sentido.

Cmo organizar las jugadas segn sus similitudes para acelerar la bsqueda de jugadas idnticas? Pues en una tabla de jugadas (NODO ***tabla), en donde anotaremos las direcciones de memoria de todas las jugadas que no hayan sido borradas.

Por ejemplo, si B=3 y hay 8 combinaciones de traslado de personas, creamos una tabla de 16 filas (las pares para las de sentido DERECHO y las impares para el resto).

Si queremos desregistrar una jugada de esta tabla (porque la vamos a borrar, por ejemplo), al nodo le recordamos la fila y la columan en que estn. As optimizamos ms an el uso de CPU.

Las ventajas de esta tabla son evidentes a la hora de buscar jugadas iguales y determinar si es repetida o no. Si ahora tenemos un total de n jugadas repartidas en 2*f filas, la eficiencia ser de O(n). Todo un adelanto. Veamos algunos ejemplos que lo grafican, en cuanto a desempeo del programa:

CASOTIEMPO SIN USO DE TABLATIEMPO CON USO DE TABLA

8m,8c,3b100

9m,9c,3b420

10m,10c,3b2560

11m,11c,3b12020

LIMITACIONES DE ESTE PROGRAMA

Para ciertos valores de parmetros mi programa se cae. Por ejemplo, funciona de lo ms bien para 190m,190c y 3b, a veces falla con 191m, 191c y 3b y siempre se cae con 192m,192c y 3b. La razn de esto me es desconocida.

Si fuera problema de software (mi programa), por qu funciona con 8m,8m,3b; 100m,100c y 3b etc...? Tal vez el s.o. no tolera a mi programa calculando casos como 191m,191c y 3b y s con 190m,190c y 3b.

En ningn modo me estoy excusando, puesto que el programador debe adapatarse al computador y no ste a aqul.

Cuando M > C, no hay problema alguno.

Antes de irme, algunos casos con los que he probado mi programa:

CASO (M,C,B)TIEMPO DE CPUMEMORIA RAM EMPLEADA

180,180,30396 KB

190,190,30420 KB

191,191,3S.O. informa de errores-

200000,199999,30(25587 jugadas) 4818.8 MB

500000,499999,30(68965 jugadas) 44542.8 MB