八皇后問題
在國際象棋的棋盤上,按照國際象棋的規則,擺放8個皇后,使之“和平共處”。如圖所示,在3-D上有一個皇后,則綠色區域中都不能再放置皇后了。
最暴力的方法就是使用八個for,但是很明顯,這種方法效率太低。
對於放置了皇后的位置,仔細觀察棋盤可以發現每一列(行)只能有一個皇后,每一個主(次)對角線上也只能有一個皇后,這樣需要標記:行-row,列-col,主對角線-(n+row-col),次對角線-(row+col)
注意:關於對角線的一點說明:
這裏以次對角線爲例:數字相同的表示一條次對角線,所以對於一個8x8的棋盤來說,一共有2x8-1條次對角線。
流程圖:
基於流程圖,利用遞歸的思想,c++實現如下,這裏的皇后的個數是在主函數中設置的8,個數可以改,但意義不大。。。。。
在遞歸回溯的過程中清空了標記,是爲了繼續搜索,找到所有的解。
#include <iostream>
#include <vector>
using namespace std;
class EightQueen {
public:
EightQueen(int nQueen) {
this->nQueen = nQueen;
inColumn.resize(nQueen, false);
mainDiagonal.resize(2 * nQueen - 1, false);
minorDiagonal.resize(2 * nQueen - 1, false);
}
~EightQueen() {}
int process() {
int *path = new int[nQueen];
calculate(path, 0);
delete[] path;
return 0;
}
void calculate(int *path, int row) {
if (row == nQueen) {
solution.push_back(vector<int>(path, path + nQueen));
return;
}
for (int col = 0; col < nQueen; col++) {
if (canLay(row, col)) {//當前位置可放置
path[row] = col;//標記放置的位置
inColumn[col] = true;//當前皇后所在列
minorDiagonal[row+col] = true;//皇后所在位置的橫縱座標之和對應的次對角線
mainDiagonal[nQueen-1+row-col] = true;//皇后所在位置的橫縱座標之和對應的主對角線
calculate(path, row + 1);//下一行上的皇后
//break;//去掉搜索所有的解!
inColumn[col] = false;
minorDiagonal[row+col] = false;
mainDiagonal[nQueen-1+row-col] = false;
}
}
}
bool canLay(int row, int col) {
return !inColumn[col] && !minorDiagonal[row + col] && !mainDiagonal[nQueen - 1 + row - col];
}
void print() {
for (int i = 0; i < solution.size(); i++) {
cout << "solution " << i << " : " << endl;
for (int row = 0; row < nQueen; row++) {
for (int col = 0; col < solution[i][row]; col++) {
cout << "O ";
}
cout << "X ";
for (int col = solution[i][row]+1; col < nQueen; col++) {
cout << "O ";
}
cout << endl;
}
cout << endl << endl;
}
}
private:
int nQueen;
vector<bool> inColumn;
vector<bool> mainDiagonal;
vector<bool> minorDiagonal;
vector<vector<int> > solution;
};
int main()
{
EightQueen queen(8);
queen.process();
queen.print();
return 0;
}