Sei sulla pagina 1di 8

MISIONEROS Y CANBALES

Autor... Juan Carlos San Martin Bravo


Id........ 01626604
Fecha.. 18 de noviembre de 2002
Email... necrosis_gangrena@hotmail.com
Web.... http://www2.netexplora.com/atila/ing.htm

Para 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.htm
Ten 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 1611-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:
arreglo
3 0

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
combinaciones, cuya estructura es la siguiente:
struct l
{
int m;

lista

ligada

de

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


//indica cuntos misioneros hay en el bote

int c;
int id;
struct l *izq;
struct l *der;
};

//dem con los canbales


//identidad de la jugada (de 0 a n...)

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:
m
c
id

3
0
0

2
1
1

0
3
2

2
0
3

1
1
4

0
2
5

1
0
6

0
1
7

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:
CASO
8m,8c,3b
9m,9c,3b
10m,10c,3
b
11m,11c,3
b

TIEMPO SIN USO DE TABLA


10
42
256

TIEMPO CON USO DE TABLA


0
0
0

1202

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 CPU

180,180,3
0
190,190,3
0
191,191,3 S.O. informa de errores
200000,199999,30 (25587
jugadas)
48
500000,499999,30 (68965
jugadas)
445

MEMORIA RAM
EMPLEADA
396 KB
420 KB
18.8 MB
42.8 MB

Potrebbero piacerti anche