[Algorithm Series (7)]: Backtracking

table of Contents

1. Backtracking

Two, algorithm application

51. N Queen


1. Backtracking

Back tracking (exploration and backtracking) is a selective search method, also known as heuristic method, which searches forward according to the selection criteria to achieve the goal. But when you explore a certain step, you find that the original choice is not good or the goal is not achieved, so you go back one step and choose again. This technique of going back and going again if you fail to get through is the backtracking method, and the point of a certain state that satisfies the backtracking condition This is called the "backtrack point."

Solving a backtracking problem is actually a traversal process of a decision tree . You only need to think about 3 questions:

1. Path: It is the choice that has been made.

2. Selection list: that is, the choices you can make currently.

3. End condition: It is the condition that reaches the bottom of the decision tree and can no longer make a choice.

The basic framework of the backtracking algorithm:

result = []
def backtrack(路径, 选择列表):
    if 满足结束条件:
        result.add(路径)
        return
    
    for 选择 in 选择列表:
        做选择
        backtrack(路径, 选择列表)
        撤销选择

When we talk about the traversal of a binary tree, we often call the operation before the recursion a preorder traversal, and the operation at the end of the recursion is a postorder traversal. What is the relationship between these two traversals and our backtracking algorithm? We can see that there are two key operations in the backtracking algorithm template: making selections and canceling selections . The selection is to add the current node to the path, so we need to traverse in advance. If we have traversed the current branch, we need to go back to the previous node and continue to traverse the next branch, so we need to cancel the selection, and this can just be achieved by subsequent traversal. Post-order traversal is also equivalent to the operation performed by returning to the current node in recursion.

Therefore, the pre-order traversal code is executed at the time point before entering a certain node, and the post-order traversal code is executed at the time point after leaving a certain node . As long as we make a choice before the recursion and cancel the choice just now after the recursion , we can get the selection list and path of each node correctly.

It can also be seen from this that the time complexity of the backtracking algorithm can not be lower than O(N!), because exhausting the entire decision tree is unavoidable. This is also a feature of the backtracking algorithm. Unlike dynamic programming, which has overlapping sub-problems that can be optimized, the backtracking algorithm is purely brute force and the complexity is generally high .

Two, algorithm application

51. N Queen

  • Title description

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-queen problem. Given an integer n, return solutions to all different n queen problems. Each solution includes a clear pawn placement plan for the n-queen problem, where'Q' and'.' represent the queen and the empty position, respectively.

示例:
输入:4
输出:[
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
  • Problem-solving ideas

This problem is essentially the same as the full permutation problem. Each level of the decision tree represents each row on the chessboard; the choice that each node can make is to place a queen in any column of the row.

  • C++ algorithm implementation
bool isValid(const vector<string> &board,const int &row,const int &col){
    int c=board[0].length();
    int r=board.size();
    for(int i=0;i<r;++i){
        if(board[i][col]=='Q'){
            return false;
        }
    }

    // 检查右上方是否有皇后互相冲突
    for (int i = row - 1, j = col + 1;
            i >= 0 && j < c; i--, j++) {
        if (board[i][j] == 'Q')
            return false;
    }
    // 检查左上方是否有皇后互相冲突
    for (int i = row - 1, j = col - 1;
            i >= 0 && j >= 0; i--, j--) {
        if (board[i][j] == 'Q')
            return false;
    }

    return true;
}


void backtrack(vector<vector<string>> &res,
               vector<string> &board,const int &row){
    if(row==board.size()){
        res.push_back(board);
        return ;
    }

    int n=board[0].length();
    for(int i=0;i<n;++i){
        if(!isValid(board,row,i)){
            continue;
        }

        board[row][i]='Q';
        backtrack(res,board,row+1);
        board[row][i]='.';
    }
}


vector<vector<string>> solveNQueens(int n) {
    vector<vector<string>> res;
    vector<string> board(n, string(n, '.'));
    backtrack(res,board,0);

    return res;
}

Reference link:

Xiaobai takes you to learn--backtracking algorithm Xiaobai CV

Detailed backtracking algorithm

Guess you like

Origin blog.csdn.net/wxplol/article/details/108512444