八皇后问题
在一个8x8的棋盘上,每行每列防止棋子“皇后”,”皇后“不能在同一行,同一列同一条斜线上。
对于这个问题通常的做法是:
1. 在一行第一个位置放置一个
2. 遍历第二行,如果找到第一个可放置的位置,则放置,遍历下一行。否则跳转到上一行遍历下一个位置。
3. 一直重复直到所有的位置都被遍历完。
为了便于说明,下面使用4皇后说明。
00 | 01 | 02 | 03 |
10 | 11 | 12 | 13 |
20 | 21 | 22 | 23 |
30 | 31 | 32 | 33 |
0 | |||
2 | |||
22 | |||
6 |
-2 | |||
22 | |||
2 |
可以得出:正对角线坐标和范围为0~(n-1)*2(2为皇后数量)
,总个数为2n-1
,负对角线的差范围-(n-1)~(n-1)
,总个数为2n-1
个。.
对于4皇后问题的解的完整处理过程如下:
代码实现:
n=4
副对角线上的元素为-3~3
为了能处理负数,统一给代码加上n-1
,详情查看代码rightDiagonal[row-col+norm]
#include <iostream>
using namespace std;
class ChessBoard{
private:
const bool available;
const int squares,norm; //norm为了将副对角线差变换到非负数
bool *column,*leftDiagonal,*rightDiagonal;
int *positionInRow,howMany;
void putQueen(int);
ostream & printBoard(ostream &);
void initializeBoard();
public:
ChessBoard();
ChessBoard(int);
~ChessBoard();
void findSolution();
};
ChessBoard::~ChessBoard() {
delete [] positionInRow;
delete [] column;
delete [] leftDiagonal;
}
ChessBoard::ChessBoard():available(true),squares(8),norm(squares-1){
initializeBoard();
}
ChessBoard::ChessBoard(int n):available(true),squares(n),norm(squares-1) {
initializeBoard();
}
void ChessBoard::initializeBoard() {
int i;
column = new bool[squares]; //放置行
positionInRow = new int[squares]; //放置位置
leftDiagonal = new bool[squares*2-1]; //左边斜线
rightDiagonal = new bool [squares*2-1]; //右边斜线
for(i = 0;i<squares;i++)
positionInRow[i] = -1;
for(i=0;i<squares;i++)
column[i] = available;
for(i=0;i<squares*2-1;i++)
leftDiagonal[i] = rightDiagonal[i] = available;
howMany = 0;
}
void ChessBoard::putQueen(int row) {
cout<<"函数开始:当前行为: "<<row<<"行,遍历不同的列col"<<endl;
for (int col = 0; col < squares; col++){
cout<<"for循环:循环开始在"<<row<<"行,"<<col<<"列!"<<endl;
if(column[col] == available &&leftDiagonal [row+col] == available &&rightDiagonal[row-col+norm] == available) {
cout<<"判断:经判断"<<col<<"列能放,列放置位置: "<<"("<<row<<","<<col<<")"<<"进入下一行:"<<row+1<<endl;
//放置皇后在row
positionInRow[row] = col;
column[col] = !available;
leftDiagonal[row+col] = !available;
rightDiagonal[row-col+norm] = !available;
if (row < squares-1)
putQueen(row+1);
else{
printBoard(cout);
howMany+=1;
cout<<"找到第"<<howMany<<"个结果"<<endl;
}
column[col] = available;
leftDiagonal[row+col] = available;
rightDiagonal[row-col+norm] = available;
}
if(col==squares-1)
{
if(row-1>=0)
cout<<"当前行遍历完成!跳到上一行"<<row-1<<endl;
}
}
}
ostream & ChessBoard::printBoard(ostream &os) {
// cout<<"当前行为: "<<col<<"\n";
return os;
}
void ChessBoard::findSolution() {
putQueen(0);
cout<<"\n";
cout<<howMany<<" Solutions found.\n";
}
int main() {
ChessBoard c1(4);
c1.findSolution();
return 0;
}
输出如下:
函数开始:当前行为: 0行,遍历不同的列col
for循环:循环开始在0行,0列!
判断:经判断0列能放,列放置位置: (0,0)进入下一行:1
函数开始:当前行为: 1行,遍历不同的列col
for循环:循环开始在1行,0列!
for循环:循环开始在1行,1列!
for循环:循环开始在1行,2列!
判断:经判断2列能放,列放置位置: (1,2)进入下一行:2
函数开始:当前行为: 2行,遍历不同的列col
for循环:循环开始在2行,0列!
for循环:循环开始在2行,1列!
for循环:循环开始在2行,2列!
for循环:循环开始在2行,3列!
当前行遍历完成!跳到上一行1
for循环:循环开始在1行,3列!
判断:经判断3列能放,列放置位置: (1,3)进入下一行:2
函数开始:当前行为: 2行,遍历不同的列col
for循环:循环开始在2行,0列!
for循环:循环开始在2行,1列!
判断:经判断1列能放,列放置位置: (2,1)进入下一行:3
函数开始:当前行为: 3行,遍历不同的列col
for循环:循环开始在3行,0列!
for循环:循环开始在3行,1列!
for循环:循环开始在3行,2列!
for循环:循环开始在3行,3列!
当前行遍历完成!跳到上一行2
for循环:循环开始在2行,2列!
for循环:循环开始在2行,3列!
当前行遍历完成!跳到上一行1
当前行遍历完成!跳到上一行0
for循环:循环开始在0行,1列!
判断:经判断1列能放,列放置位置: (0,1)进入下一行:1
函数开始:当前行为: 1行,遍历不同的列col
for循环:循环开始在1行,0列!
for循环:循环开始在1行,1列!
for循环:循环开始在1行,2列!
for循环:循环开始在1行,3列!
判断:经判断3列能放,列放置位置: (1,3)进入下一行:2
函数开始:当前行为: 2行,遍历不同的列col
for循环:循环开始在2行,0列!
判断:经判断0列能放,列放置位置: (2,0)进入下一行:3
函数开始:当前行为: 3行,遍历不同的列col
for循环:循环开始在3行,0列!
for循环:循环开始在3行,1列!
for循环:循环开始在3行,2列!
判断:经判断2列能放,列放置位置: (3,2)进入下一行:4
找到第1个结果
for循环:循环开始在3行,3列!
当前行遍历完成!跳到上一行2
for循环:循环开始在2行,1列!
for循环:循环开始在2行,2列!
for循环:循环开始在2行,3列!
当前行遍历完成!跳到上一行1
当前行遍历完成!跳到上一行0
for循环:循环开始在0行,2列!
判断:经判断2列能放,列放置位置: (0,2)进入下一行:1
函数开始:当前行为: 1行,遍历不同的列col
for循环:循环开始在1行,0列!
判断:经判断0列能放,列放置位置: (1,0)进入下一行:2
函数开始:当前行为: 2行,遍历不同的列col
for循环:循环开始在2行,0列!
for循环:循环开始在2行,1列!
for循环:循环开始在2行,2列!
for循环:循环开始在2行,3列!
判断:经判断3列能放,列放置位置: (2,3)进入下一行:3
函数开始:当前行为: 3行,遍历不同的列col
for循环:循环开始在3行,0列!
for循环:循环开始在3行,1列!
判断:经判断1列能放,列放置位置: (3,1)进入下一行:4
找到第2个结果
for循环:循环开始在3行,2列!
for循环:循环开始在3行,3列!
当前行遍历完成!跳到上一行2
当前行遍历完成!跳到上一行1
for循环:循环开始在1行,1列!
for循环:循环开始在1行,2列!
for循环:循环开始在1行,3列!
当前行遍历完成!跳到上一行0
for循环:循环开始在0行,3列!
判断:经判断3列能放,列放置位置: (0,3)进入下一行:1
函数开始:当前行为: 1行,遍历不同的列col
for循环:循环开始在1行,0列!
判断:经判断0列能放,列放置位置: (1,0)进入下一行:2
函数开始:当前行为: 2行,遍历不同的列col
for循环:循环开始在2行,0列!
for循环:循环开始在2行,1列!
for循环:循环开始在2行,2列!
判断:经判断2列能放,列放置位置: (2,2)进入下一行:3
函数开始:当前行为: 3行,遍历不同的列col
for循环:循环开始在3行,0列!
for循环:循环开始在3行,1列!
for循环:循环开始在3行,2列!
for循环:循环开始在3行,3列!
当前行遍历完成!跳到上一行2
for循环:循环开始在2行,3列!
当前行遍历完成!跳到上一行1
for循环:循环开始在1行,1列!
判断:经判断1列能放,列放置位置: (1,1)进入下一行:2
函数开始:当前行为: 2行,遍历不同的列col
for循环:循环开始在2行,0列!
for循环:循环开始在2行,1列!
for循环:循环开始在2行,2列!
for循环:循环开始在2行,3列!
当前行遍历完成!跳到上一行1
for循环:循环开始在1行,2列!
for循环:循环开始在1行,3列!
当前行遍历完成!跳到上一行0