LeetCode51.N皇后,面试题 08.12.八皇后 原题链接:N皇后 原题链接:八皇后
1. 需要了解的知识点
全排列模板(回溯)
dfs()
{
if() //出口
{
return ;
}
for(int i=0;i<n;i++) //列举所有情况
{
if(!pd[i])
{
pd[i]=1;
dfs();
pd[i]=0; //回溯
}
}
}
相关视频链接:【算法】dfs刷题实战1
2. 难点:
皇后不能放置在对角线上
3. 思路
把这道题考虑成全排列问题,比如八个皇后在棋盘上放置的位置可以是
第一行第1个 | 第一行第1个 | 第一行第1个
第二行第2个 | 第二行第3个 | 第一行第4个
第三行第3个 | 第二行第2个 | 第一行第2个
、、、、、、 、、、、、 、、、、、
第八行第8个 | 第二行第8个 | 第一行第8个
考虑完了行列不同,接下来考虑对角线,如果两个皇后在一条对角线上,必定两个点的坐标满足 abs(行1-行2)==abs(列1-列2)
4. 代码注释
变量定义的解释
vector<vector<string>> vecvec
:需要返回的目标字符串数组
vector<int> pd(n,-1)
:储存行号和列号,pd[0]下标0代表行号,pd[0]的值代表列号,不必定义二维数组,但一维数组理解可能麻烦一点。
int n
:多少个皇后,棋盘的长宽
int count
:当前的行号
class Solution {
public:
void dfs(int n, vector<int> pd,int count,vector<vector<string>>& vecvec)
{
/*count为第多少行,pd[count]为第多少列*/
if (count >= n) /*出口*/
{
/*用于测试pd里面的值
for (auto i : pd)
cout << i << " "; cout<<endl;
*/
/*打印放入目标数组中*/
vector<string> vec;
for (auto i : pd)
{
string str;
for (int j = 0; j < n; j++)
{
if (i != j)
str.push_back('.');
else
str.push_back('Q');
}
vec.push_back(str);
}
vecvec.push_back(vec);
return ;
}
for (int i = 0; i < n; i++) /*排列所有情况*/
{
pd[count] = i; /*第count行将皇后放到第i列*/
int bean = 1; /*标记是否可以放皇后,1可以放*/
for (int k = 0; k < count; k++) /*之前放过的所有皇后的坐标,遍历会不会攻击当前皇后*/
{
if ( pd[k] == pd[count]) /*属于同一列*/
{
bean = 0; /*标记为不能放*/
}
if (abs(count-k) == abs(i-pd[k])) /* 行-行 == 列-列 */
bean = 0; /*对角线(核心代码)*/
}
if (bean == 1)
{
dfs(n, pd, count + 1, vecvec); /*递归*/
}
}
}
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> vecvec;
vector<int> pd(n,-1); /*初始化*/
/*递归深搜*/
dfs(n, pd,0,vecvec);
return vecvec;
}
};
4. 总结反思
此题没有回溯,之前在书上看的算法记得可以用一维数组搞定。过程中全程都在修改abs那行,测试可以去掉abs那行看,会发现全排列表现的很明显。
测试代码
int main()
{
vector<vector<string>> vec;
vec=solveNQueens(8);
cout << "***" << vec.size() << endl;
for (auto i : vec)
{
for (auto j : i)
{
for (auto k : j)
cout << k << " ";
cout << endl;
}
cout << endl;
}
}
测试图片
![图片名称](https://i-blog.csdnimg.cn/blog_migrate/71bbc63488b7449cb02ffc5555d8b879.png)