N 皇后问题是一个古老而著名的问题, 是回溯算法(back track)的典型案例。问题描述如下:
N x N 的棋盘上放置N个皇后。 要求同一行中, 同一列中, 以及对角线上(包括正负对角线)只能有一个皇后, 否则就会发生clash的情况而失败。 问解决方案?
解决思路如下:
(1)逐列扫描, 从最左边的列开始, 总共有N个queens。
(2)如果所有的queens 都被安全放置了, 就返回true。
(3)对于给定的列, 尝试所有的行, 此时行是变量, 注意此时此列的左边的所有的列都放置了皇后, 此时我们只需要对当前列的所有行进行扫描, 寻找放置的可行的行,所谓可行就是不会与左边的皇后产生clash, 条件为三个方向, 不同列(当然会满足), 不同行, 不同上斜对角线, 不同下斜对角线。
(4) 一旦放置好当前的列一个的皇后, 就进入下一列放置。 但是一旦没有产生可行解的时候, 就要回溯(backtrack)到上一列, 重新放置上一列的皇后, 继续重复上述步骤, 直至成功, 否则输出失败。
参考程序如下(4 * 4)参考至geeks for geeks:
#include <iostream> #include <cstdio> 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 <iostream> 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; }
运行结果如下:
时间: 2024-10-05 00:12:28