The input of the problem is the N size of the board and the output its solution.
This is a nontrivial problem and there are many approaches to solve it such as constraint programming, logic programming or genetic algorithms.
The solution range is N^2*N so a brute force algorithm would take much time to solve it. For instance, in the N=3 case there would be (3*3)^3=387420489 possible placements.
I made a depth-first search (DFS) and backtracking (BT) algorithm to solve it.
In my proposed solution, the root of the tree represents the empty board and each node of the tree represents a different board configuration. On the other hand, the algorithm explores the branches of the tree (using DFS) that have a promising solution (BT), otherwise the branch is pruned and another one is explored.
In the following tree an example of the algorithm for N=4 is shown:
I implemented the algorithm in Java, for values of N larger than 14 you might need to increase the size of the java stack by adding -Xss8m in the java options as for these values there is a very deep recursion and it could be overflowed. The code is shown below:
/** * N-Queens Problem: Using Depth-First Search & Backtracking * @author gru */ public class Main { public static void NQueen(int N, int[][] board, int i, int j, boolean found) { //if found we return the result if (!found) { //check if the current position is valid if (IsValid(board, i, j)) { board[i][j] = 1; //Uncomment to track the partial results //System.out.println("[+]New Queen added at (" + i + "," + j + ")"); //PrintBoard(board); //check if this was the last queen if (i == N - 1) { found = true; PrintBoard(board); } //call the next iteration NQueen(N, board, i + 1, 0, found); } else { //if the position is not valid //if it was the last row we do backtracking while (j >= N - 1) { int[] a = BackTracking(board, i, j); i = a[0]; j = a[1]; //Uncomment to track the partial results //System.out.println("[+]Rolled back at (" + i + "," + j + ")"); //PrintBoard(board); } //we do the next call NQueen(N, board, i, j + 1, false); } } } public static int[] BackTracking(int[][] board, int i, int j) { int[] a = new int[2]; for (int x = i; x >= 0; x--) { for (int y = j; y >= 0; y--) { //seeks the last queen if (board[x][y] != 0) { //deletes the last queen and returns the position board[x][y] = 0; a[0] = x; a[1] = y; return a; } } } return a; } public static boolean IsValid(int[][] board, int i, int j) { int x; //check if there is any queen in the same column for (x = 0; x < board.length; x++) { if (board[i][x] != 0) { return false; } } //check if there is any queen in the same row for (x = 0; x < board.length; x++) { if (board[x][j] != 0) { return false; } } //check if there is any queen in the diagonals if (!IsSafeDiag(board, i, j)) { return false; } return true; } public static boolean IsSafeDiag(int[][] board, int i, int j) { int ii = i; int jj = j; while (jj >= 0 && ii >= 0 && ii < board.length && jj < board.length) { if (board[ii][jj] != 0) { return false; } jj++; ii++; } ii = i; jj = j; while (jj >= 0 && ii >= 0 && ii < board.length && jj < board.length) { if (board[ii][jj] != 0) { return false; } jj--; ii--; } ii = i; jj = j; while (jj >= 0 && ii >= 0 && ii < board.length && jj < board.length) { if (board[ii][jj] != 0) { return false; } jj--; ii++; } ii = i; jj = j; while (jj >= 0 && ii >= 0 && ii < board.length && jj < board.length) { if (board[ii][jj] != 0) { return false; } jj++; ii--; } return true; } public static void PrintBoard(int[][] board) { System.out.print(" "); for (int j = 0; j < board.length; j++) { System.out.print(j); } System.out.print("\n"); for (int i = 0; i < board.length; i++) { System.out.print(i); for (int j = 0; j < board.length; j++) { if (board[i][j] == 0) { System.out.print(" "); } else { System.out.print("Q"); } } System.out.print("\n"); } } public static void main(String[] args) { //we parse the input, which is the size of the problem int N = Integer.parseInt(args[0]); //we create a board int[][] board = new int[N][N]; //we call the method that solves the problem NQueen(N, board, 0, 0, false); } }
my improved version for values of N = 35 executed in 3min 58 sec
ReplyDelete/*
* Elimination of recursion.
* Data structure used is the table, cause we need to represent a single data ( column index ) in each row
*/
package deptfirstsearch;
import java.util.Scanner;
/**
*
* @author hangouby@gmail.com
*/
public class DeptFirstSearch {
//Method that solve our problem
private static long NQueen(int n, int[] board, int i, boolean correct, long failure) {
board[i] = 1;
//if the solution found (true), return the result
while (!correct) {
//Add a new queen if the current position is valid
if (IsValid(board, i)) {
//check if this was the last queen
if (i == n - 1)
return failure;
//call the next iteration
i++;
board[i] = 1;
}else { //position is not valid
//seeks the last queen and remove it
while (board[i] == n) {
failure++;
i--;
} //we do the next call
board[i]++;
correct = false;
}
}
return failure;
}
/*
//method that remove the last queen and return it position
private static int[] SeekLastQueen(int[][] board, int i, int j) {
int[] a = new int[2];
for (int x = i; x >= 0; x--) {
for (int y = j; y >= 0; y--) {
//seeks the last queen
if (board[x][y] != 0) {
//deletes the last queen and returns the position
board[x][y] = 0;
a[0] = x;
a[1] = y;
return a;
}
}
}
return a;
}*/
//Method that check whether the current position is valid
private static boolean IsValid(int[] board, int i) {
for (int j = i - 1, x = 1; j > -1; j--, x++)
if (board[i] == board[j] || board[i] + x == board[j] || board[i] - x == board[j])
return false;
return true;
}
//Method that print board
private static void PrintBoard(int[] board) {
System.out.print(" ");
for (int j = 0; j < board.length; j++)
System.out.print(" " + j + " ");
System.out.println();
for (int i = 0; i < board.length; i++) {
System.out.print(" " + i + " ");
for (int j = 1; j <= board.length; j++)
if (board[i] != j)
System.out.print(" ");
else
System.out.print(" Q ");
System.out.println();
}
}
public static void main(String[] args) {
// Determine the chess board size
Scanner input = new Scanner(System.in);
System.out.println("Enter the chess board size\n");
int n = input.nextInt();
//Creation of board
int[] board = new int[n];
//call solve method
long failure = NQueen(n, board, 0, false, 0);
System.out.println("Number of failure : " + failure);
//Printing board
PrintBoard(board);
}
}
thanx
ReplyDeleteI've used a depth-first search in spy girlfriend software. We can discuss this problem if you are interested.
ReplyDelete