51. N皇后

n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 8-queens.png 上图为 8 皇后问题的一种解法。 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q''.' 分别代表了皇后和空位。 示例:

  1. 输入: 4
  2. 输出: [
  3. [".Q..", // 解法 1
  4. "...Q",
  5. "Q...",
  6. "..Q."],
  7. ["..Q.", // 解法 2
  8. "Q...",
  9. "...Q",
  10. ".Q.."]
  11. ]
  12. 解释: 4 皇后问题存在两个不同的解法。

提示:

  • 皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一到七步,可进可退。(引用自 百度百科 - 皇后

解题思路

回溯算法
按层按列遍历,检查每个当前位置是否合法,不合法的位置则跳过,合法的位置作为当前选择,并进入下一层。回溯时,即撤销本层当列的选择,继续遍历下一列。
image.png

  1. class Solution {
  2. public:
  3. vector<vector<string>> res;
  4. int len;
  5. vector<vector<string>> solveNQueens(int n) {
  6. len = n;
  7. vector<string> solveOne(n,string(n,'.'));
  8. recurDep(0,solveOne);
  9. return res;
  10. }
  11. void recurDep(int row,vector<string>& solveOne){
  12. //终止条件
  13. if(row == len) {
  14. res.push_back(solveOne);
  15. return;
  16. }
  17. for(int col = 0;col < len;col++) {
  18. //只有合适的位置才能放置,排除其他不合法的选择
  19. if(checkPosi(row,col,solveOne)) {
  20. //当前选择
  21. solveOne[row][col] = 'Q';
  22. //进行下一决策
  23. recurDep(row + 1,solveOne);
  24. //回溯,撤销选择
  25. solveOne[row][col] = '.';
  26. }
  27. }
  28. }
  29. //检查位置(row,col)是否可以放置皇后
  30. bool checkPosi(int row,int col,vector<string>& solveOne) {
  31. //检查列是否有皇后互相冲突
  32. for (int i = 0;i < row;i++)
  33. if(solveOne[i][col] == 'Q') return false;
  34. //检查右上方是否有皇后冲突
  35. for(int i = row-1,j = col + 1; i >= 0&& j < len;i--,j++)
  36. if(solveOne[i][j] == 'Q') return false;
  37. //检查左上方是否有皇后冲突
  38. for(int i = row-1,j = col - 1; i >= 0&& j >= 0;i--,j--)
  39. if(solveOne[i][j] == 'Q') return false;
  40. return true;
  41. }
  42. };