第一种方法:
思路:我们以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;
}
}
}
}