1. 题⽬链接:51.N皇后
2. 题⽬描述:
3. 解法:
算法思路:
⾸先,我们在第⼀⾏放置第⼀个皇后,然后遍历棋盘的第⼆⾏,在可⾏的位置放置第⼆个皇后,然后 再遍历第三⾏,在可⾏的位置放置第三个皇后,以此类推,直到放置了n个皇后为⽌。
我们需要⽤⼀个数组来记录每⼀⾏放置的皇后的列数。在每⼀⾏中,我们尝试放置⼀个皇后,并检查 是否会和前⾯已经放置的皇后冲突。如果没有冲突,我们就继续递归地放置下⼀⾏的皇后,直到所有 的皇后都放置完毕,然后把这个⽅案记录下来。
在检查皇后是否冲突时,我们可以⽤⼀个数组来记录每⼀列是否已经放置了皇后,并检查当前要放置 的皇后是否会和已经放置的皇后冲突。对于对⻆线,我们可以⽤两个数组来记录从左上⻆到右下⻆的 每⼀条对⻆线上是否已经放置了皇后,以及从右上⻆到左下⻆的每⼀条对⻆线上是否已经放置了皇 后。
• 对于对⻆线是否冲突的判断可以通过以下流程解决:
1. 从左上到右下:相同对⻆线的⾏列之差相同;
2. 从右上到左下:相同对⻆线的⾏列之和相同。
因此,我们需要创建⽤于存储解决⽅案的⼆维字符串数组solutions ,⽤于存储每个皇后的位置的 ⼀维整数数组queens ,以及⽤于记录每⼀列和对⻆线上是否已经有皇后的布尔型数组columns 、 diagonals1 和diagonals2 。
递归函数设计:void dfs(vector> &solutions, vector &queens, int &n, int row, vector &columns, vector &diagonals1, vector &diagonals2)
参数:row(当前需要处理的⾏数);
返回值:⽆;
函数作⽤:在当前⾏放⼊⼀个不发⽣冲突的皇后,查找所有可⾏的⽅案使得放置n个皇后后不发⽣冲 突。
递归函数流程如下:
1. 结束条件:如果row 等于n ,则表⽰已经找到⼀组解决⽅案,此时将每个皇后的位置存储到字 符串数组board 中,并将board 存储到solutions 数组中,然后返回;
2. 枚举当前⾏的每⼀列,判断该列、两个对⻆线上是否已经有皇后:
a. 如果有皇后,则继续枚举下⼀列;
b. 否则,在该位置放置皇后,并将columns 、 diagonals1 和diagonals2 对应的位置 设为true ,表⽰该列和对⻆线上已经有皇后:
i. 递归调⽤dfs 函数,搜索下⼀⾏的皇后位置。如果该⽅案递归结束,则在回溯时需要将 columns 、 diagonals1 和diagonals2 对应的位置设为false ,然后继续枚举 下⼀列;
C++算法代码:
class Solution
{
public:
vector<vector<string>> answer; //总答案
vector<string>key; //单个选项
int size;
int hang[10] = { 0 }, lie[10] = { 0 }; //行列状态数组
int z_xie[100] = { 0 }, f_xie[100] = { 0 }; //正反斜线状态数组
void dfs(int t)
{
bool temp = false; //判断一行内是否有合适位置
//出口
if (t == size)
{
answer.push_back(key);
return;
}
for (int i = 0; i < size; i++)
{
//四个方向上都没有皇后,则可以放
if (!hang[t] && !lie[i] && !z_xie[t - i + size] && !f_xie[t + i])
{
temp = true;
hang[t] = 1, lie[i] = 1;
z_xie[t - i + size] = 1, f_xie[t + i] = 1;
key[t][i] = 'Q';
dfs(t + 1);
key[t][i] = '.';
hang[t] = 0, lie[i] = 0;
z_xie[t - i + size] = 0, f_xie[t + i] = 0;
}
}
}
vector<vector<string>> solveNQueens(int n)
{
size = n;
//初始化
string a;
//开空间
key.resize(n);
//初始化
for(int i=0;i<n;i++)
{
key[i].append(n,'.');
}
dfs(0);
return answer;
}
};
Java算法代码:
class Solution
{
boolean[] checkCol, checkDig1, checkDig2;
List<List<String>> ret;
char[][] path;
int n;
public List<List<String>> solveNQueens(int _n)
{
n = _n;
checkCol = new boolean[n];
checkDig1 = new boolean[n * 2];
checkDig2 = new boolean[n * 2];
ret = new ArrayList<>();
path = new char[n][n];
for (int i = 0; i < n; i++)
Arrays.fill(path[i], '.');
dfs(0);
return ret;
}
public void dfs(int row)
{
if (row == n)
{
// 添加结果
List<String> tmp = new ArrayList<>();
for (int i = 0; i < n; i++)
{
tmp.add(new String(path[i]));
}
ret.add(new ArrayList<>(tmp));
}
for (int col = 0; col < n; col++)
{
// 判断能不能放
if (checkCol[col] == false && checkDig1[row - col + n] == false &&
checkDig2[row + col] == false)
{
path[row][col] = 'Q';
checkCol[col] = checkDig1[row - col + n] = checkDig2[row +
col] = true;
dfs(row + 1);
// 恢复现场
path[row][col] = '.';
checkCol[col] = checkDig1[row - col + n] = checkDig2[row +
col] = false;
}
}
}
}