首先就是最经典的N皇后问题
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],
["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]
解释: 4 皇后问题存在两个不同的解法。
首先,比如在1a处放置一个皇后,则a列和1行以及斜线都不能放置皇后
这里使用mark二维数组来标记已访问的点,标记为1
要实现这个功能,不如创建一个方法push_down_queen(),
参数传入放置的皇后的坐标,和mark数组
因为有八个方位,上下左右,左上,左下,右上,右下
这里用两个数组来实现(dx[],dy[])
private:
void push_down_the_queen(int x, int y, vector<vector<int>>& mark) {//放置皇后及其攻击范围的数组
static const int dx[] = { -1,1,0,0,-1,-1,1,1 };//移动坐标数组
static const int dy[] = { 0,0,-1,1,-1,1,-1,1 };
mark[x][y] = 1;//标记当前放置皇后的位置为一
for (int i = 1; i < mark.size(); i++) {//标记攻击范围为一,因为数组中的"0"位置已经放置了皇后,且已置零
for (int j = 0; j < 8; j++) {//八个方向
int new_x = x + i*dx[j];//往上置零,则坐标一直往上移动(用i*dx[j]实现)
int new_y = y + i*dy[j];
if (new_x >= 0 && new_x < mark.size() && new_y >= 0 && new_y < mark.size()) {
mark[new_x][new_y] = 1;
}
}
}
}
一次内循环置一次"1"
黑色的"1"对应i=1时
绿色的"1"对应i=2时
红色的"1"对应i=3时
因为有八个方位,所以内循环8次
1-1.假如在1a放置了皇后,则按照顺序只能在2c放置皇后,如此任由它进行下去,有可能会出现放置的皇后数 ! = n 的情况,这时候就需要回溯了
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<int>> mark;//标记数组,指定不能放置的位置
vector<string> location;//存储某个摆放结果
vector<vector<string>> result;
for (int i = 0; i < n; i++) {
mark.push_back((vector<int>()));//为后续二级数组push做前提,否则无法访问二级数组
for (int j = 0; j < n; j++) {
mark[i].push_back(0);
}
location.push_back("");
location[i].append(n, '.');//初始化
}
generate(0, n, mark, result, location);
return result;
}
location数组作为当前情况的记录数组,result数组作为最终满足放置的皇后数==n的结果数组,
先初始化矩阵,然后进入递归generate()
private://k为当前的皇后标号,n皇后,mark标记数组,result结果数组,location用于存储当前放置的皇后的数组
void generate(int k, int n, vector<vector<int>>& mark, vector<vector<string>>& result, vector<string>& location) {
if (k == n) {
result.push_back(location);//当符合条件时,放入结果数组中
return;
}
for (int i = 0; i < n; i++) {//按顺序尝试1至n列
if (mark[k][i] == 0) {
vector<vector<int>> temp_mark = mark;//镜像数组,便于回溯
location[k][i] ='Q';//放置当前皇后
push_down_the_queen(k, i, mark);//更新标记数组
//vector<string> 数组可以像location一样操作,即用单引号,可以类似二维数组操作
generate(k + 1, n, mark, result, location);//递归
mark = temp_mark;//回溯
location[k][i] = '.';
}
}
}
递归的结束条件即放置的皇后数== n的情况,按照1-1的算法思想,需要按列的顺序试着放入皇后,这时候就要用到mark标记数组作为准入条件,先建立一个镜像mark,而后放置皇后,再进入递归,回溯的话就要用到刚刚的镜像数组mark了。