第一種方法:
思路:我們以4皇后問題爲例:用回溯法,設一個二維數組作爲棋盤,一個位置一個位置地試,首先我們將第一個皇后放入(0,0)中,根據規則,第0行中不能再放其他皇后,那麼下一個要放在第二行,根據規則,第1行第一二列被第一個皇后監視,所以只能放入(1,2)中,繼續下一行,我們發現沒有位置可以放,那麼說明上一個皇后要換位置,所以回退一行,將上一個皇后放入(1,3),再找下一個位置,如此反覆,直到求出全部解。
代碼:
queens.cpp
#include<iostream>
using namespace std;
const int max_board = 30; //最多可解決30皇后問題
class Queens {
public:
Queens(int size); //構造函數
bool is_solved() const; //判斷是否已經解決了問題
void print() const; //打印出結果
bool unguarded(int col) const; //判斷這個位置是否可以放新的皇后
void insert(int col); //放入新的皇后
void remove(int col); //回退
int board_size; //要解決的是board_size皇后問題
private:
int count; //表示放入的皇后數,也表示行數
bool queen_square[max_board][max_board]; //用二維數組來表示棋盤
};
void Queens::insert(int col) //放入新的皇后
{
queen_square[count++][col] = true; //將這個位置的值變爲true,表示放入了皇后,count加一
}
Queens::Queens(int size) //構造函數,參數爲要判斷的皇后大小
{
board_size = size;
count = 0; //初始時未放入皇后,在第0行
for (int row = 0; row < board_size; row++)
for (int col = 0; col < board_size; col++)
queen_square[row][col] = false; //開始時給每個位置賦初值false,表示還未放皇后
}
bool Queens::unguarded(int col) const //判斷這個位置是否可以放新的皇后
{
int i;
bool ok = true; //表示是否可以放入皇后
for (i = 0; ok && i < count; i++)
ok = !queen_square[i][col]; //檢測在同一列中是否有皇后
for (i = 1; ok && count - i >= 0 && col - i >= 0; i++)
ok = !queen_square[count - i][col - i]; //檢測主對角線上是否有皇后
for (i = 1; ok && count - i >= 0 && col + i < board_size; i++)
ok = !queen_square[count - i][col + i]; //檢測輔對角線上是否有皇后
return ok;
}
void Queens::print() const //打印結果
{
int row,col;
int count = 0;
for(col = 0;col < board_size;col++) cout << "--";
cout << "--\n";
for(row = 0;row < board_size;row++)
{
for(col = 0;col < board_size;col++)
{
count++;
if(queen_square[row][col])
{
cout << " Q";
} //一行一行檢測,如果值是true則說明該位置存了皇后
else cout << " ."; //如果值是false則說明該位置存了皇后
if(board_size == count)
{
cout << endl;
count = 0;
}
}
}
}
void Queens::remove(int col) //回退
{
queen_square[--count][col] = false;
}
bool Queens::is_solved() const //判斷是否已解決
{
if(count == board_size) return true; //如果放入皇后的個數等於問題中皇后的個數則說明問題已經解決
else return false;
}
main.cpp
#include "queens.cpp"
void solve_from(Queens &configuration) //解決問題
{
if (configuration.is_solved()) configuration.print(); //如果問題已被解決,則打印出結果
else
for (int col = 0; col < configuration.board_size; col++) //遍歷數組
{
if (configuration.unguarded(col))
{
configuration.insert(col); //如果該位置沒有被監控則放入皇后
solve_from(configuration); //遞歸
configuration.remove(col); //如果問題已經有一個解,那麼打印出這個解,回退,繼續尋找下一個解
}
}
}
void print_information()
{
cout << "This program determines all the ways to place n queens\n" << "on an n by n chessboard,where n <= " << max_board << endl;
}
int main()
{
int board_size;
print_information();
cout << "What is the size of the board? " << flush;
cin >> board_size; //輸入要解決幾皇后問題
if (board_size < 0 || board_size > max_board)
cout << "The number must be between 0 and " << max_board << endl; //如果輸入的值不合法則輸出提示信息
else {
Queens configuration(board_size); //實例一個對象
solve_from(configuration); //解決問題
}
}
第二種方法:
思路:跟第一種方法類似,將二維數組換成一維數組,需要四個一維數組,一個用來存每行中皇后的位置的列數,兩個用來表示該條對角線上是否已經被皇后監視,還有一個用來表示該列中是否被皇后監視。主函數與方法一代碼相同。
代碼:
queens.cpp
#include<iostream>
using namespace std;
const int max_board = 30; //最多可解決30皇后問題
class Queens {
public:
Queens(int size); //構造函數
bool is_solved() const; //判斷是否已經解決了問題
void print() const; //打印出結果
bool unguarded(int col) const; //判斷這個位置是否可以放新的皇后
void insert(int col); //放入新的皇后
void remove(int col); //回退
int board_size; //要解決的是board_size皇后問題
private:
int count; //表示放入的皇后數,也表示行數
bool col_free[max_board]; //用來表示該列中是否被皇后監視
bool upward_free[2 * max_board - 1];//用來表示主對角線上是否已經被皇后監視
bool downward_free[2 * max_board - 1];//兩個用來表示輔對角線上是否已經被皇后監視
int queen_in_row[max_board]; //用來存放入的皇后的列數
};
Queens::Queens(int size) //構造函數,參數爲要判斷的皇后大小
{
board_size = size;
count = 0;
for (int i = 0; i < board_size; i++) col_free[i] = true;
for (int j = 0; j < (2 * board_size - 1); j++) upward_free[j] = true;
for (int k = 0; k < (2 * board_size - 1); k++) downward_free[k] = true; //開始時所有值都爲true,表示可以放皇后
}
void Queens::insert(int col) //放入新的皇后
{
queen_in_row[count] = col; //將列數存入數組中
col_free[col] = false; //該位置的列被監視
upward_free[count + col] = false; //該位置的主對角線被監視
downward_free[count - col + board_size - 1] = false;//該位置的輔對角線被監視
count++;
}
bool Queens::unguarded(int col) const //判斷這個位置是否可以放新的皇后
{
return col_free[col] && upward_free[count + col] && downward_free[count - col + board_size - 1]; //如果列,主對角線,副對角線中有一個被監視,則不能放皇后
}
void Queens::remove(int col) //回退
{
count--;
col_free[col] = true;
upward_free[count + col] = true;
downward_free[count - col + board_size-1] = true;//將這個位置恢復
}
bool Queens::is_solved() const //判斷是否已解決
{
if(count == board_size) return true; //如果放入皇后的個數等於問題中皇后的個數則說明問題已經解決
else return false;
}
void Queens::print() const //打印結果
{
int i,j;
int count = 0;
for(i = 0;i < board_size;i++) cout << "--";
cout << "--\n";
for(i = 0;i < board_size;i++)
{
for(j = 0;j < board_size;j++)
{
count++;
if(j == queen_in_row[i]) cout << " Q"; //找出存皇后的列數,輸出Q
else cout << " .";
if(board_size == count)
{
cout << endl;
count = 0;
}
}
}
}