一、前言
问题来源LeetCode 51,难度:困难
问题链接:https://leetcode-cn.com/problems/n-queens
二、题目
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。即任意两个皇后都不能处于同一行、同一列或同一斜线上。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
三、思路
用回溯法就可以了。提供了2种解法,都是用回溯思想,第二种方法编码方法更好些。
四、编码实现
//==========================================================================
/**
* @file : 51_SolveNQueens.h
* @title: N皇后
* @purpose : n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
* 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
* 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
* 示例 1:
* 输入: 4
* 输出: [
* [".Q..", // 解法 1
* "...Q",
* "Q...",
* "..Q."],
*
* ["..Q.", // 解法 2
* "Q...",
* "...Q",
* ".Q.."]
* ]
*
*
* 来源:力扣(LeetCode)难道:困难
* 链接:https://leetcode-cn.com/problems/n-queens
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
//==========================================================================
#include <vector>
#include <iostream>
using namespace std;
#define NAMESPACE_SOLVENQUEENS namespace NAME_SOLVENQUEENS {
#define NAMESPACE_SOLVENQUEENSEND }
NAMESPACE_SOLVENQUEENS
// 方法一:回溯算法
class Solution_1
{
public:
vector<vector<string>> solveNQueens(int n)
{
vector<string> arr(n, string(n, ' '));
vector<vector<string>> ret;
solveNQueens(n, 0, ret, arr);
return ret;
}
void solveNQueens(const int n, const int k, vector<vector<string>>& ret, vector<string>& arr)
{
if (k >= n)
{
ret.push_back(arr);
return;
}
const int checkCount = 5; //需要验证条件个数
static int t[checkCount][2] = { {0,-1},{0,1},{1,0},{1,1},{1,-1} };
vector<pair<int, int>> v(n * 3, make_pair(-1, -1));
for (int i = 0; i < n; ++i)
{
if (arr[k][i] == ' ')
{
arr[k][i] = 'Q';
int index = 0;
v[index++] = make_pair(k, i);
int h = k, x = i;
for (int j = 0; j < checkCount; ++j)
{
h = k + t[j][0];
x = i + t[j][1];
while (h >= 0 && h < n && x >= 0 && x < n)
{
if (arr[h][x] == ' ')
{
v[index++] = make_pair(h, x);
arr[h][x] = '.';
}
h += t[j][0];
x += t[j][1];
}
}
solveNQueens(n, k + 1, ret, arr);
//恢复
for (int j = 0; j < v.size(); ++j)
{
if (v[j].first != -1)
{
arr[v[j].first][v[j].second] = ' ';
v[j].first = -1;
v[j].second = -1;
}
else
{
break;
}
}
}
}
}
};
// 方法二:回溯算法
class Solution_2
{
private:
vector<vector<string>> res;//存结果
vector<string> tmp;//存棋盘
public:
vector<vector<string>> solveNQueens(int n)
{
string line(n, '.');//既然一行一行试,那就一行一行存
solveNQueens(line, 0, n);//从第0行开始
return res;
}
private:
//试某一行
void solveNQueens(string& line, int row, int n)
{
if (tmp.size() == n)//棋盘绘制够n行存进结果,不用继续试了
{
res.push_back(tmp);
return;
}
for (int i = 0; i < n; ++i)//一格一格,每格都要试
{
if (checkAll(row, i, n)) //符合条件了
{
line[i] = 'Q'; //就把当前试的这一格放皇后
tmp.push_back(line); //然后把这一行绘制进棋盘
line[i] = '.'; //棋盘的下一行应该是没有皇后的
solveNQueens(line, row + 1, n);//去试下一行
tmp.pop_back(); //接下来要去试下一格,刚才绘制进去的那一行删掉
}
}
}
bool checkAll(int row, int col, int n)
{
for (int i = 1; i <= row; ++i)
{
if (col - i >= 0 && tmp[row - i][col - i] == 'Q')
return false;
if (col + i < n && tmp[row - i][col + i] == 'Q')
return false;
if (tmp[row - i][col] == 'Q')
return false;
}
return true;
}
};
//
// 测试 用例 START
void test(const char* testName, int n, int expect)
{
Solution_1 S1;
Solution_2 S2;
vector<vector<string>> result1 = S1.solveNQueens(n);
vector<vector<string>> result2 = S2.solveNQueens(n);
// 粗略验证一下
if (result1.size() == expect && result2.size() == expect)
{
cout << testName << ", solution passed." << endl;
}
else
{
cout << testName << ", solution failed." << endl;
}
}
// 测试用例
void Test1()
{
int n = 1;
int expect = 1;
test("Test1()", n, expect);
}
void Test2()
{
int n = 2;
int expect = 0;
test("Test2()", n, expect);
}
void Test3()
{
int n = 3;
int expect = 0;
test("Test3()", n, expect);
}
// 测试用例
void Test4()
{
int n = 4;
int expect = 2;
test("Test4()", n, expect);
}
// 测试用例
void Test5()
{
int n = 5;
int expect = 10;
test("Test5()", n, expect);
}
// 测试用例
void Test6()
{
int n = 6;
int expect = 4;
test("Test6()", n, expect);
}
NAMESPACE_SOLVENQUEENSEND
// 测试 用例 END
//
void SolveNQueens_Test()
{
NAME_SOLVENQUEENS::Test1();
NAME_SOLVENQUEENS::Test2();
NAME_SOLVENQUEENS::Test3();
NAME_SOLVENQUEENS::Test4();
NAME_SOLVENQUEENS::Test5();
NAME_SOLVENQUEENS::Test6();
}
执行结果: