Problema de las ocho reinas

Movimientos posibles de una reina en un tablero de 4×4.
Una posible solución entre las 92 posibles soluciones en un tablero de 8×8.

El problema de las ocho reinas es un pasatiempo en el que se colocan ocho reinas sin que se amenacen. Fue propuesto por el ajedrecista alemán Max Bezzel en 1848[cita requerida]. En el juego del ajedrez la reina amenaza a aquellas piezas que se encuentren en su misma fila, columna o diagonal. El juego de las 8 reinas consiste en colocar sobre un tablero de ajedrez ocho reinas sin que estas se amenacen entre ellas. Para resolver este problema emplearemos un esquema vuelta atrás (o Backtracking).

Historia

El problema fue originalmente propuesto en 1848 por el ajedrecista Max Bezzel. Durante años, muchos matemáticos, incluyendo a Gauss y a Georg Cantor, han trabajado en él y lo han generalizado a n-reinas. Las primeras soluciones fueron ofrecidas por Franz Nauck en 1850. Nauck también se abocó a las n-reinas (en un tablero de nxn de tamaño arbitrario). En 1874, S. Günther propuso un método para hallar las soluciones usando determinantes, y J.W.L. Glaisher redefinió su aproximación.

Edsger Dijkstra usó este problema en 1972 para ilustrar el poder de la llamada programación estructurada. Publicó una descripción muy detallada del desarrollo del algoritmo de backtracking, "depth-first".

Este acertijo apareció en el popular juego de computadora de los '90 llamado "The 7th Guest".

Planteamiento del Problema

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 la reina 3 y la 6 estarían 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 resuelto, 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-l o i+j=k+l

j-l=i-k o j-l=k-i

Teniendo en cuenta todas estas consideraciones, podemos aplicar el esquema retroactivamente para colocar las ocho reinas de una manera realmente eficiente. Para ello, reformulamos el problema como problema de búsqueda en un árbol. Decimos que en un vector V_{1\dots k} de enteros entre 1 y 8 es k-prometedor, para 0\leq k\leq8 , si ninguna de las k reinas colocadas en las posiciones (1,V_1),(2,V_2),\dots,(k,V_k) 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, 0\leq k\leq8, sea G=(N,A)\, el grafo dirigido tal que (U,V)\in A si y solo si existe un entero k, con 0\leq k\leq8 tal que

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. Esto 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) controladas por las reinas que ya están puestas.

Descripción del algoritmo

A continuación se muestra el algoritmo que soluciona nuestro problema, en el cual sol_{1\dots8} es un vector global. Para imprimir todas las soluciones, la llamada inicial es \mathrm{reinas}(0,\empty,\empty,\empty).

procedimiento \mathrm{reinas}(k,col,diag45,diag135)\,

//sol_{1\dots k} es k-prometedor//
//col = \{sol_i\mid 1\leq i\leq k\}//
//diag45=\{sol_i-i+1\mid1\leq i\leq k\}//
//diag135=\{sol_i+i-1\mid 1\leq i\leq k\}//
si k=8\, entonces //un vector 8-prometedor es una solución//
escribir sol\,
si no //explorar las extensiones (k+1)-prometedoras de sol//
para j\leftarrow 1 hasta 8\, hacer
si j\notin col y j-k\notin diag45 y j+k\notin diag135 entonces
sol_{k+1}\leftarrow j//sol_{1\dots k+1} es (k+1)-prometedor//
\mathrm{reinas}\left(k+1,col\cup\{j\},diag45\cup\{j-k\},diag135\cup\{j+k\}\right)

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, que 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.

Implementación

A continuación se muestra una posible implementación del anterior algoritmo en C++.

#include <iostream>
#include <sstream>
#include <cstdio>
#include <vector>
#include <algorithm>
#define NREINAS 8 // dimensiones del tablero y número de reinas
using namespace std;
vector<int> sol;
int nro_sol=1;


inline bool contiene(const vector<int>& v, const int val)
{
    return find(v.begin(), v.end(), val) != v.end();
}

void reinas(int k, vector<int> col, vector<int> diag45, vector<int> diag135)
{
    if( k == NREINAS )
    {
	printf("%3d:", nro_sol++);
        for(int j=0; j<NREINAS; j++)
	    cout << " (" << j+1 << "," << sol[j] << ")";
        cout << endl;
    }
    else
    {
        for(int j=1; j<=NREINAS; j++)
            if( !contiene(col, j) && !contiene(diag45, j-k) && !contiene(diag135, j+k) )
            {
                sol[k] = j;

                col.push_back(j);
                diag45.push_back(j-k);
                diag135.push_back(j+k);

                reinas(k+1,col, diag45, diag135);

                col.pop_back();
                diag45.pop_back();
                diag135.pop_back();
            }
    }
}

int main() {
    cout << "SOLUCIONES AL PROBLEMA DE LAS " << NREINAS << " REINAS";
    sol.resize(NREINAS);
    reinas(0, vector<int>(), vector<int>(), vector<int>());

    return 0;
}

El problema de las n reinas

El problema de las ocho reinas se puede plantear de modo general como problema de las n reinas. El problema consistiría en colocar n reinas en un tablero de ajedrez de n \times n de tal manera que ninguna de las reinas quede atacando a otra.

Su análisis y solución es isomorfo al de las ocho reinas.

Número de soluciones

n: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 24 25 26
distintas: 1 0 0 1 2 1 6 12 46 92 341 1,787 9.233 45.752 28.439.272.956.934 275.986.683.743.434 2.789.712.466.510.289
todas las soluciones: 1 0 0 2 10 4 40 92 352 724 2.680 14.200 73.712 365.596 227.514.171.973.736 2.207.893.435.808.352 22.317.699.616.364.044 87

Soluciones al problema de las ocho reinas

El problema de las ocho reinas tiene 92 soluciones, de las cuales 12 son esencialmente distintas, es decir las 92 soluciones existentes se pueden obtener a partir de simetrías y rotaciones de las 12 soluciones únicas, que se muestran a continuación:

Solución única 1
Solución única 2
Solución única 3
Solución única 4
Solución única 5
Solución única 6
Solución única 7
Solución única 8
Solución única 9
Solución única 10
Solución única 11
Solución única 12

Referencias

Véase también

Enlaces externos

Enlaces a soluciones

This article is issued from Wikipedia - version of the Saturday, January 16, 2016. The text is available under the Creative Commons Attribution/Share Alike but additional terms may apply for the media files.