N queen problem | Backtracking: N permutation

The n queen problem studies how to place n queens on an n×n chessboard and make the queens unable to attack each other.

The picture above shows a solution to the 8 queens problem.

Given an integer n, return solutions to all different n queen problems.

Each solution contains a clear pawn placement plan for the n-queen problem, where'Q' and'.' represent the queen and the empty position respectively.

Example:

Input: 4
Output: [
 [".Q..", // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]


Explanation: 4 There are two different solutions to the queen problem.

leetcode link: https://leetcode-cn.com/problems/n-queens/


1. General idea

        Respectively traverse each situation where n queens can be placed, and record the situation that meets the conditions of the question. Since traversal is involved, we can consider the backtracking method. Sort out the order of the traversal: first specify the i-th row, corresponding to the number of backtracking levels i, and traverse the row j in each level of traversal (as long as j has not been selected and no conflict will occur).

        Use pos[i] to record the number of columns in the ith row, that is, place a queen in (i, pos[i]).

        Use vis[j] to record whether the jth column has been selected.

        Write a check() function to  determine whether the selected position conflicts with the selected position.

        It can be seen that the result is stored in a vector, we named it ans, and this situation should be placed in ans at the end of each backtracking. The situation should be sorted into the form of vector<string>, and we execute it in a print() function  .


Second, the realization of the backtracking algorithm

/* 对于一共有 n 行的棋盘,我们对第 i (0:n-1)行做选择*/
void backtrack(int i, int n) {
    /* 回溯的终点:所有行已经选择完毕 */
    if (i == n) {
        print(n);
        return;
    }
    /* 依次遍历每一列 */
    for (int j = 0; j < n; j++) {
        /* 排除已经被选择 或 会产生冲突的情况 */
        if (vis[j] || !check(i, j))
            continue;

        vis[j] = true;  //列被选择需要做标记
        pos[i] = j;  //记录第 i 行选择了第 j 列
        backtrack(i + 1, n);  //继续进行对下一列的选择
        vis[j] = false;
    }
}

Three, the realization of print() function

         Nothing special, just use the corresponding implementation of the pos array record.

/* 对于已经到回溯终点的情况
 * 我们将记录的结果处理为题目需要的图形储存 */
void print(int n) {
    vector<string> temp; //记录此种情况下完整的答案
    /* 依次构建 n 行 */
    for (int i = 0; i < n; i++) {
        string s;
        /* 依次存储每行的 n 个元素 */
        for (int j = 0; j < n; j++) {
            if (j == pos[i])
                s.push_back('Q');
            else
                s.push_back('.');
        }
        temp.push_back(s);  //将此行存入答案
    }
    ans.push_back(temp);  //将此种情况存入总的答案
}

 Fourth, the realization of check() function

         To determine whether the currently selected point (i, j) conflicts with the previous i row, the order of our backtracking is row-wise, and the column selection is also used to prevent repeated selection through the vis array, so there is no case of the same column in the same row. It only needs to judge whether it is on an oblique side, and traverse the previous i-1 selections in turn to see if it is on a 45° oblique side. Remember to add the absolute value~

bool check(int i, int j) {
    for (int t = 0; t < i; t++)
        if (abs(i - t) == abs(j - pos[t]))
            return false;
    return true;
}

Five, supplement and analysis 

       The above can be said to be an implementation of selective backtracking , but the n-queen problem can also be implemented using sorted backtracking . The selection of the corresponding column in the n rows is mutually exclusive, then the selection of that column corresponds to all sorting situations, and then the conflicts can be excluded.

Complete code:

#include <string>
#include <algorithm>
#include <vector>

using namespace std;

class Solution {
public:
    bool vis[100] = {false};
    int pos[100] = {0};
    vector<vector<string>> ans;

    vector<vector<string>> solveNQueens(int n) {
        backtrack(0, n);
        return ans;
    }

    void backtrack(int i, int n) {
        if(i == n) {
            print(n);
            return;
        }

        for(int j = 0; j < n; j++) {
            if(vis[j] || !check(i, j))
                continue;

            vis[j] = true;
            pos[i] = j;
            backtrack(i + 1, n);
            vis[j] = false;
        }
    }

    bool check(int i, int j) {
        for(int t = 0; t < i; t++)
            if(abs(i - t) == abs(j - pos[t]))
                return false;
        return true;
    }

    void print(int n) {
        vector<string> temp;
        for(int i = 0; i < n; i++) {
            string s;
            for(int j = 0; j < n; j++) {
                if(j == pos[i])
                    s.push_back('Q');
                else
                    s.push_back('.');
            }
            temp.push_back(s);
        }
        ans.push_back(temp);
    }
};

 

Guess you like

Origin blog.csdn.net/weixin_43787043/article/details/106064598