Está en la página 1de 8

Se trata de un programa clásico de algorítmica.

Depende de con la eficiencia con la que quieras resolverlo tendrás que hacer unas u
otras podas.
La idea es hacer "backtracking", es decir, prueba y error.
Haz esto:
-Una matríz de 8x8 de booleanos (1 hay reina, 0 no hay reina)
-Una función que compruebe si una reina está en una posición incorrecta (pasas la
matriz y la posición y comprueba que no ataca/está siendo atacada... es facil.
-Una función recursiva que reciba varios parametros... seria algo así.
bool funcion(int colocadas, bool matriz[8][8], int fila)
{
if (colocadas=8)
return 1;
if(fila>=8 )
fila=0
for (int i =0; i<8;i++)
if (!atacada(matriz,fila,i) )
{
matriz[fila][i]=1;
if(funcion(colocadas+1,matriz,fila+1))
return 1 ;
matriz[fila][i]=0;
}
return 0;
}

Esto lo acabo de hacer ahora mismo. Es un poco dificil de ver al principio. La idea es
que si puede colocar una reina en un sitio, la coloca y se llama a si misma. Si el
resultado es 1 (la siguiente función y sicesivas pudieron colocarla) entonces todo está
terminado, si es 0 (no se peude colocar desde esa posición) cambia la reina de sitio (a la
siguiente casilla) y vuelve a intentarlo. Si no puede colocar en ninguna de las 8 casillas
de la fila, entonces devuelve 0 para que el que la yamó haga los cambios pertinentes.

void buscar(int i,int col[], boolean fila[], boolean dgn[], boolean dgi[])
{
int j;
j = 0;//indice de fila
q = FALSE;//variable de respuesta
do {//bucle
if(i!=c){//condicion para la columna en que esta digitada la reina
if (fila[j] && dgn[i+j] && dgi[7+i-j]) {//validacion si no hay nada en fila,y diagonales
col[i] = j; fila[j] = dgn[i+j] = dgi[7+i-j] = FALSE;//pone la reina
if (i<7) { //Dice que no hay nada en ese columna
buscar(i+1,col,fila,dgn,dgi);//Recursividad o pasa a otra columna
if (!q)//anterior no cuadra
fila[j] = dgn[i+j] = dgi[7+i-j] = TRUE;//borrar reina
} else q = TRUE; /* encuentra la solucion */ }
}else buscar(i+1,col,fila,dgn,dgi);//Pasa a otra columna
j++;//contador
} while (!q && j<8);//condicion
}

int main(void)//principal
{
int i;//contador
char e;//Variable para preguntar salida
int col[8];//Columna
boolean fila[8],dgn[15], dgi[15];//Filas, Diagonal Normal e inversa
for (i = 0; i < 8; i++) fila[i] = TRUE;//Blanquea todas las filas
for (i = 0; i < 15; i++) dgn[i] = dgi[i] = TRUE;//blanquea diagonales
Board(); //hacer el tablero
col[c] = f; fila[f] = dgn[c+f] = dgi[7+c-f] = FALSE;//inserte la reina digitada
buscar(0,col,fila,dgn,dgi); //la busqueda
if(q){//condicion para sabar si hay posiciones
for (i = 0; i < 8; i++){//envia coordenadas para dibujar fichas
dibujar(i,col[i]);}//envia coordenadas para dibujar fichas
}else {ventana(2);}//llama a ventana de mensajes para usuarios
setcolor(5);//Color al Texto
//gotoxy(10,28);cout<<"Desea Salir (s/n)"<<flush;//Desea seguir
//gotoxy(28,28);cin>>e;//Coje la respuesta
outtextxy(100,400,"Para repetir precione S, Para Salir precione Cualquier tecla");
e = getch();//toma el valor de la tecla pulsada anteriormente
if(e==\'s\',e==\'S\'){main();}//si es no vuelve a ejecutar elprograma haciendo con main
closegraph();//cerrar grafico
return 0;
}
Lista de soluciones
(Enviadas por Joaquim Marzà y Francisco Saenz-Díez).

En la siguiente lista los números indican en qué lugar poner las reinas en cada una de las
filas del tablero, por orden. Por ejemplo, la primera solución representa una reina en la
primera casilla de la primera fila, una en la quinta casilla de la segunda fila, una en la
octava casilla de la tercera fila...

1 -- 15863724
2 -- 16837425
3 -- 17468253
4 -- 17582463
5 -- 24683175
6 -- 25713864
7 -- 25741863
8 -- 26174835
9 -- 26831475
10 -- 27368514
11 -- 27581463
12 -- 28613574
13 -- 31758246
14 -- 35281746
15 -- 35286471
16 -- 35714286
17 -- 35841726
18 -- 36258174
19 -- 36271485
20 -- 36275184
21 -- 36418572
22 -- 36428571
23 -- 36814752
24 -- 36815724
25 -- 36824175
26 -- 37285146
27 -- 37286415
28 -- 38471625
29 -- 41582736
30 -- 41586372
31 -- 42586137
32 -- 42736815
33 -- 42736851
34 -- 42751863
35 -- 42857136
36 -- 42861357
37 -- 46152837
38 -- 46827135
39 -- 46831752
40 -- 47185263
41 -- 47382516
42 -- 47526138
43 -- 47531682
44 -- 48136275
45 -- 48157263
46 -- 48531726
47 -- 51468273
48 -- 51842736
49 -- 51863724
50 -- 52468317
51 -- 52473861
52 -- 52617483
53 -- 52814736
54 -- 53168247
55 -- 53172864
56 -- 53847162
57 -- 57138642
58 -- 57142863
59 -- 57248136
60 -- 57263148
61 -- 57263184
62 -- 57413862
63 -- 58413627
64 -- 58417263
65 -- 61528374
66 -- 62713584
67 -- 62714853
68 -- 63175824
69 -- 63184275
70 -- 63185247
71 -- 63571428
72 -- 63581427
73 -- 63724815
74 -- 63728514
75 -- 63741825
76 -- 64158273
77 -- 64285713
78 -- 64713528
79 -- 64718253
80 -- 68241753
81 -- 71386425
82 -- 72418536
83 -- 72631485
84 -- 73168524
85 -- 73825164
86 -- 74258136
87 -- 74286135
88 -- 75316824
89 -- 82417536
90 -- 82531746
91 -- 83162574
92 -- 84136275

Como cada reina puede amenazar a todas las reinas que estén en la misma fila, cada una
ha de situarse en una fila diferente. Podemos representar las 8 reinas mediante un
vector[1-8], teniendo en cuenta que cada índice del vector representa una fila y el valor
una columna. Así cada reina estaría en la posición (i, v[i]) para i = 1-8.

Ejemplo de dos reinas amenazadas en el tablero de 4 por 4.

El vector (3,1,6,2,8,6,4,7) significa que la reina 1 esta en la columna 3, fila1; la reina 2


en la columna 1, fila 2; la reina 3 en la columna 6, fila 3; la reina 4 en la columna 2, fila
4; etc... Como se puede apreciar esta solución es incorrecta ya que estarían la reina 3 y
la 6 en la misma columna. Por tanto el vector correspondería a una permutación de los
ocho primeros números enteros.
El problema de las filas y columnas lo tenemos cubierto, ¿pero qué ocurre con las
diagonales? Para las posiciones sobre una misma diagonal descendente se cumple que
tienen el mismo valor fila − columna, mientras que para las posiciones en la misma
diagonal ascendente se cumple que tienen el mismo valor fila + columna. Así, si
tenemos dos reinas colocadas en posiciones (i,j) y (k,l) entonces están en la misma
diagonal si y solo si cumple:

i−j=k−loi+j=k+l

j−l=i−koj−l=k−i

Con todas las consideraciones tenidas en cuenta podemos aplicar el esquema de vuelta
atrás para implementar las ocho reinas de una manera realmente eficiente. Para ello,
reformulamos el problema como un problema de búsqueda en un árbol. Decimos que en
un vector de enteros entre 1 y 8 es k-prometedor, para , si ninguna de
las k reinas colocadas en las posiciones amenaza a
ninguna de las otras. Las soluciones a nuestro problema se corresponden con aquellos
vectores que son 8-prometedores.

Establecimiento del Algoritmo

Sea N el conjunto de vectores de k-prometedores, , sea el


grafo dirigido tal que si y solo si existe un entero k, con tal
que

 U es k-prometedor
 V es (k + 1)-prometedor
 Ui = Vi para todo

Este grafo es un árbol. Su raíz es el vector vacío correspondiente a k = 0. sus hojas son o
bien soluciones (k = 8), o posiciones sin salida (k < 8). Las soluciones del problema de
las ocho reinas se pueden obtener explorando este árbol. Sin embargo no generamos
explícitamente el árbol para explorarlo después. Los nodos se van generando y
abandonando en el transcurso de la exploración mediante un recorrido en profundidad.

Esquema reducido del árbol de soluciones.


Hay que decidir si un vector es k-prometedor, sabiendo que es una extensión de un
vector (k − 1)-prometedor, únicamente necesitamos comprobar la última reina que haya
que añadir. Este se puede acelerar si asociamos a cada nodo prometedor el conjunto de
columnas, el de diagonales positivas (a 45 grados) y el de diagonales negativas (a 135
grados) controlados por las reinas que ya están puestas.

Descripción del Algoritmo

A continuación se muestra el algoritmo que arroja la solución de nuestro problema, en


el cual es un vector global. Para imprimir todas las soluciones, la llamada
inicial es .

procedimiento

// es k-prometedor//

// //

//

//

//

//

si entonces //un vector 8-prometedor es


una solución//

escribir

si no //explorar las extensiones (k + 1)-


prometedoras de sol//

para hasta hacer

si y y
entonces

// es (k + 1)-
prometedor//
El algoritmo comprueba primero si k = 8, si esto es cierto resulta que tenemos ante
nosotros un vector 8-prometedor, lo cual indica que cumple todas las restricciones
originando una solución. Si k es distinto de 8, el algoritmo explora las extensiones (k +
1)-prometedoras, para ello realiza un bucle, el cual va de 1 a 8, debido al número de
reinas. En este bucle se comprueba si entran en jaque las reinas colocadas en el tablero,
si no entran en jaque, se realiza una recurrencia en la cual incrementamos k (buscamos
(k + 1)-prometedor) y añadimos la nueva fila, columna y diagonales al conjunto de
restricciones. Al realizar la recurrencia hemos añadido al vector sol una nueva reina la
cual no entra en jaque con ninguna de las anteriores, además hemos incrementado el
conjunto de restricciones añadiendo una nueva fila, columna y diagonales (una positiva
y otra negativa) prohibidas.

El problema de las n Reinas

El problema de las 8 Reinas es generalizado por el problema de las n Reinas. El


problema consiste en colocar n Reinas en un tablero de ajedrez de de tal
manera que ninguna de las Reinas quede atacando a otra.

Su análisis y solución es isomorfo al de las 8 Reinas.

2.7.2.- Backtracking.
Ejemplo: el problema de las ocho reinas
Un tablero de ajedrez, el cual tiene un total de 64 casillas
(8 filas x 8 columnas). El problema consiste en situar
ocho reinas en el tablero de tal forma que no se den jaque
entre ellas. Una reina puede dar jaque a aquellas reinas
que se sitúen en la misma fila, columna o diagonal en la
que se encuentra dicha reina.

Solución:
· Meter la primera reina.
· Meter la segunda en una casilla que no esté atacada por
la primera reina.
· Meter la tercera en una casilla no atacada por la
primera o la segunda.
· Meter sucesivamente el resto de reinas. Si en algún
momento no puede colocarse una reina, ir deshaciendo
movimientos de las reinas ya colocadas y a partir de esa
reorganización continuar la colocación del resto de
reinas.
Funciones auxiliares:
· void asignarReinaA(int fila, int columa) => Sitúa un 1
en la casilla (Fila, Columna) indicando que está
ocupada por una reina.
· void eliminarReinaDe(int fila, int columna) => Sitúa un
0 en la casilla (Fila, Columna) indicando que esa casilla
está libre (antes estaba ocupada por una reina y ahora
deja de estarlo).
· int recibeJaqueEn(int fila, int columna) => Devuelve 1
si la casilla (Fila, Columna) recibe jaque de alguna
reina y 0 en caso contrario.
_ __
public void situarReina(int Columna)
/* Col indica en qué columna se quiere situar la reina, y
Situada es una variable que tomará el valor 1 cuando se
haya logrado ubicar correctamente a la reina
correspondiente, y 0 cuando el intento haya sido
infructuoso. */
{
int fila, situada;
if (columna > 7) {
situada=1;
return Situada;
else
{
situada=0;
fila=1;
while (!(situada) && (fila <= 7))
if (fecibeJaqueEn(fila, columna)) ++fila;
else
{
asignarReinaA(fila, columna);
situada=situarReina(columna+1);
if ( !(Situada))
{
eliminaReinaDe(fila, columna);
++fila;
}
}
}
return situada;
_ __
}

http://156.35.31.178/wiki/index.php/TP:n_reinas_-_Backtracking

También podría gustarte