N皇后
题目[leetcode 51]
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
皇后的攻击范围为:
下图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],
["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]
解释: 4 皇后问题存在两个不同的解法。
提示:
皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一到七步,可进可退。(引用自 百度百科 - 皇后 )
思路
这里设计了一张图mark来说明该位置是否能放皇后,如果mark[i][j]==1时,说明在其他的皇后攻击范围,不能下;若 ==0,则能下,那么通过这张图就能准确地试探这样的下棋方式是否可行,若不可行,则回溯到上一个棋子前,改为另一个可下的位置。
修改mark的函数为put_down_the_queen,这个函数利用方向数组的形式将皇后位置上的八个方向进行了遍历,使得后面的皇后不可在这些位置上下棋子。
实现代码如下:
void put_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++){
for(int j = 0; j < 8; j++){
int new_x = x + 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;
}
}
}
然后便是尝试性回溯的函数generate,这个主要是在一行一行的形式去摆放皇后,有以下情况出现:
①如果在该行的某位置(i, j)不在其他皇后的攻击范围上,即mark[i][j] == 0时,便可进行下一行的尝试。
②当这一行上的位置因前面皇后的摆放,均不可放入,则回溯到上一行,改为下一个可放位置,直至N个皇后均放入到棋盘中去。
展现形式如下:
实现代码如下:
void generate(int k, int n,
vector<string>& location,
vector<vector<string>> &result,
vector<vector<int>> &mark){
if(k == n){ //N个皇后均已放入时,结束递归
result.push_back(location);
return;
}
for(int i = 0; i < n; i++){ //把该行的n个位置军尝试一遍
if(mark[k][i] == 0){ //该位置可放皇后时
vector<vector<int>> temp_mark = mark; //保存未修改时的mark,有误回溯时可用
location[k][i] = 'Q'; //放皇后
put_down_the_queen(k, i, mark); //遍历皇后的攻击范围
generate(k + 1, n, location, result, mark); //进入下一行探索
mark = temp_mark; //下一行探索失败时,回溯mark
location[k][i] = '.';//拿回皇后
}
}
}
之后就是数据结构的构建和主要函数的调用。
实现代码如下:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> result;
vector<vector<int>> mark;
vector<string> location;
for(int i = 0; i < n; i++){ //构建起初的mark结构
mark.push_back((vector<int>()));
for(int j = 0; j < n; j++){
mark[i].push_back(0);
}
location.push_back("");//棋盘的构造
location[i].append(n, '.');
}
generate(0, n, location, result, mark); //函数调用
return result;
}
致谢
本章知识点和思路由小象学院相关视频提供,由本人学习并梳理得出,希望自己加深记忆的同时,也能给大家提供更多有关于一些算法的知识点。
你的点赞、评论、收藏就是对我最大的支持与鼓励,谢谢!