N 皇后问题是一个古老而著名的问题, 是回溯算法(back track)的典型案例。问题描述如下:
N x N 的棋盘上放置N个皇后。 要求同一行中, 同一列中, 以及对角线上(包括正负对角线)只能有一个皇后, 否则就会发生clash的情况而失败。 问解决方案?
解决思路如下:
(1)逐列扫描, 从最左边的列开始, 总共有N个queens。
(2)如果所有的queens 都被安全放置了, 就返回true。
(3)对于给定的列, 尝试所有的行, 此时行是变量, 注意此时此列的左边的所有的列都放置了皇后, 此时我们只需要对当前列的所有行进行扫描, 寻找放置的可行的行,所谓可行就是不会与左边的皇后产生clash, 条件为三个方向, 不同列(当然会满足), 不同行, 不同上斜对角线, 不同下斜对角线。
(4) 一旦放置好当前的列一个的皇后, 就进入下一列放置。 但是一旦没有产生可行解的时候, 就要回溯(backtrack)到上一列, 重新放置上一列的皇后, 继续重复上述步骤, 直至成功, 否则输出失败。
参考程序如下(4 * 4)参考至geeks for geeks:
#include
#include
using namespace std;
const int N = 4;
// a utility function
void printSolution(int board[N][N]) {
for(int i = 0; i < N; ++i) {
for(int j = 0; j < N; ++j) {
cout << board[i][j];
}
cout << endl;
}
}
// a utility function to chreck if a queen can
// be placed on board[row][col], note this function
// is called when 'col' queens already placed in columns
// from 0 to col - 1, so we need to check only left side
// for attacking queens
bool isSafe(int board[N][N], int row, int col) {
// check row on left side
for(int i = 0; i < col; ++i) {
if(board[row][i]) {
return false;
}
}
// check upper diagonal on left side
for(int i = row, j = col; i >= 0 && j >= 0; --i, --j) {
if(board[i][j]) {
return false;
}
}
// check lower diagonal on left side
for(int i = row, j = col; i < N && j < col; ++i, --j) {
if(board[i][j]) {
return false;
}
}
return true;
}
// a recursive utility function to solve N queen
// problem
bool solveNQUtil(int board[N][N], int col) {
// base case: if all queens are placed then return true
if(col >= N) {
return true;
}
// consider this column and try placing this queen in all rows
// one by one
for(int i = 0; i < N; i++) {
// check if queen can be placed on board
// board[i][col]
if(isSafe(board, i, col)) {
// place this queen on board[i][col]
board[i][col] = 1;
// recur to place the rest of the queens
if(solveNQUtil(board, col + 1) == true) {
return true;
}
// If placing queen on board[i][col] does
// not leads to a solution, we should remove it
board[i][col] = 0; // backtrack
}
}
// If queen cannot be placed in any row
// in this column col, then return false
return false;
}
bool solveNQ() {
int board[N][N] = {{0, 0, 0, 0}, {0, 0, 0, 0},
{0, 0, 0, 0}, {0, 0, 0, 0}};
if(solveNQUtil(board, 0) == false) {
cout << "No solution" << endl;
return false;
}
else {
printSolution(board);
return true;
}
}
// driver program
int main() {
solveNQ();
return 0;
}
运行结果如下:
参考wiki的http://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/N-Queens, 如下代码产生所有Nqueen的所有的可行解:
#include
using namespace std;
const int N = 4;
int position[N]; // 记录解决方案的N个queen的位置
// Check if a position is safe
bool isSafe(int queen_number, int row_position){ // 检查该行是否安全
// Check each queen before this one
for(int i = 0; i < queen_number; i++){ // 当前queen的左边各列的已经安全的queen
// Get another queen's row_position
int other_row_pos = position[i]; // 之前的queen存储的位置在position[i]
// Now check if they're in the same row or diagonals
if (other_row_pos == row_position || // Same row
other_row_pos == row_position - (queen_number - i) || // Same diagonal
other_row_pos == row_position + (queen_number - i)) // Same diagonal
return false;
}
return true;
}
// Recursively generate a tuple like [0 0 0 0], then [0 0 0 1] then etc...
void solve(int k)
{
if (k == N) // We placed N-1 queens (0 included), problem solved!
{
// Solution found!
cout << "Solution: ";
for (int i = 0; i < N; i++)
cout << position[i] << " ";
cout << endl;
}
else
{
for (int i = 0; i < N; i++) // Generate ALL combinations
{
// 对于当前的k(放置在k列的皇后), 会尝试玩所有的行
// Before putting a queen (the k-th queen) into a row, test it for safeness
if (isSafe(k, i)) // 可以放即执行下面的语句, 将queen k 放置在位置i处
{
position[k] = i;
// Place another queen
solve(k + 1);
}
}
}
}
int main()
{
solve(0);
return 0;
}
运行结果如下: