题目描述(困难难度)
LeetCode代码
class Solution {
public:
static const int N = 30;
char g[N][N];
bool col[N], dg[N], udg[N];
vector<vector<string>> ans;
void dfs(int u, int n) {
if (u == n) { // 输出答案,如果是修改原数组,需用bool型dfs
vector<string> sol; // sol每次都要更新
for(int i = 1; i <= n; i ++) {
string tmp = "";
for (int j = 1; j <= n; j ++) {
tmp += g[i][j];
}
sol.push_back(tmp);
}
ans.push_back(sol);
return;
}
for (int i = 1; i <= n; i ++) {
if (!col[i] && !dg[u + i - 1] && !udg[u - i + n]) {
g[u + 1][i] = 'Q'; // 从u = 1开始填
col[i] = dg[u + i - 1] = udg[u - i + n] = true;
dfs(u + 1, n);
g[u + 1][i] = '.'; // 恢复现场,这步必须有,因为这题不像排列数字那题都能被覆盖到
col[i] = dg[u + i - 1] = udg[u - i + n] = false; // 恢复现场,不影响下一个分支的搜索,这步很关键
}
}
}
vector<vector<string>> solveNQueens(int n) {
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= n ; j ++) {
g[i][j] = '.';
}
}
dfs(0, n);
return ans;
}
};
算法1
(按行枚举)
说明:对角线dg[u + i],反对角线udg[n - u + i]中的下标表示的是截距
(u, i)即(x, y)
-
对角线y = x + b, 截距b = y - x
因为我们要把b当做数组下标,所以b不能是负的,所以我们+n,保证是结果是正的 -
反对角线y = -x + b, 截距是b = y + x
核心目的:找一些合法的下标来表示dg或udg是否被标记过就可以了,所以如果你愿意,你取udg[n + n - u + i]也没有事情,只要所有(u, i)对可以映射过去就行
C++ 代码
#include <iostream>
using namespace std;
const int N = 20;
// bool数组用来判断搜索的下一个位置是否可行
// col列,dg对角线,udg反对角线
// g[N][N]用来存路径
int n;
char g[N][N];
bool col[N], dg[N], udg[N];
void dfs(int u)
{
// u == n 表示已经搜了n行,故输出这条路径
if (u == n)
{
for (int i = 0; i < n; i ++ ) puts(g[i]); // 等价于cout << g[i] << endl;
puts(""); // 换行
return;
}
//对n个位置按行搜索
for (int i = 0; i < n; i ++ )
// 剪枝(对于不满足要求的点,不再继续往下搜索)
// udg[n - u + i],+n是为了保证大于0
// 只要保证(u,i)都能映射到,+2n也没事
if (!col[i] && !dg[u + i] && !udg[n - u + i])
{
g[u][i] = 'Q';
col[i] = dg[u + i] = udg[n - u + i] = true;
dfs(u + 1);
// 恢复现场 这步很关键
col[i] = dg[u + i] = udg[n - u + i] = false;
g[u][i] = '.';
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
g[i][j] = '.';
dfs(0);
return 0;
}
算法2
(按每个元素枚举)
时间复杂度分析:每个位置都有两种情况,总共有 个位置
C++ 代码
// 不同搜索顺序 时间复杂度不同 所以搜索顺序很重要!
#include <iostream>
using namespace std;
const int N = 20;
// 因为是一个个搜索,所以加了row
int n;
char g[N][N];
bool row[N], col[N], dg[N], udg[N];
// s表示已经放上去的皇后个数
void dfs(int x, int y, int s)
{
// 处理超出边界的情况
if (y == n) y = 0, x ++ ;
// 说明已经放好了n个皇后,表示枚举完 n^2 个了
if (x == n)
{
if (s == n)
{
for (int i = 0; i < n; i ++ ) puts(g[i]);
puts("");
}
return;
}
// 不放皇后 就往下搜下一个位置
dfs(x, y + 1, s);
// 放皇后
if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n])
{
g[x][y] = 'Q';
row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;
dfs(x, y + 1, s + 1);
row[x] = col[y] = dg[x + y] = udg[x - y + n] = false;
g[x][y] = '.';
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
g[i][j] = '.';
dfs(0, 0, 0);
return 0;
}
写在最后:我的博客主要是对计算机领域所学知识的总结、回顾和思考,把每篇博客写得通俗易懂是我的目标,分享技术和知识是一种快乐 ,非常欢迎大家和我一起交流学习,有任何问题都可以在评论区留言,也期待与您的深入交流(^∀^●)