回溯法(一)——八皇后问题

回溯算法就是个多叉树的遍历问题, 关键就是在前序遍历和后序遍历的位置做⼀些操作, 算法框架如下:

void backTrack(...){
    if(满足结束条件){
        将路径加入到结果集
        return ;
    }
    for(选择 in 选择列表){
          判断选择是否合法,如果不合法则进入一下此循环(continue)
          并做选择
          进入下一层决策树(backTrack(...))
          撤销选择(也就是回溯的意思)
    }
}

  backTrack函数时,需要维护走过的[路径]和当前可以做的[选择列表],当触发[结束条件]时,将[路径]加入到结果集。

  举个例子八皇后问题,数组使用result[8]太妙了,切忌不要使用二维数组result,这样反而会增大难度,因为使用result[8]的话,每行路径在找到正确位置都是更新的最新值;如果使用二维数组的话,还要考虑当皇后回溯的时候,怎么去掉放置的位置

  • 这个题目在判断皇后位置是否合适的时候,只需要判断当前行上方的位置是否有皇后,不需要判断下面的
  • 一定要注意,数组result最后的值可能不是八皇后,可能是某个中间值,所以,不要在最后来打印八皇后,应该在8个皇后都放置好了就可以打印了。

C++版代码如下

#include <iostream>
#include <math.h>
#include <cstring>
using namespace std;

#define MAXSIZE 256


// 八皇后问题
bool isOk(int result[], int row, int col){
    // 只判断row行之前的位置,后面的不管

    // 1、判断竖方向
    for(int i = 0; i <= row - 1; i++){
        if(result[i]  == col)
            return false;
    }
    // 2、判断主对角线左方
    for(int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--){
        if(result[i] == j)
            return false;
    }

    // 3、 判断副对角线右方
    for(int i = row - 1, j = col + 1; i >= 0 && j < 8; i--, j++){
        if(result[i] == j)
            return false;
    }
    return true;
}


void eightQueen(int result[], int row){
    // 如果走到了最后一行,则代表找到了全部位置
    if(row == 8){
        for (int row = 0; row < 8; ++row) {
            for (int column = 0; column < 8; ++column) {
                if (result[row] == column)
                    cout<<"Q ";
                else
                    cout<<"* ";
            }
            cout<<endl;
        }
        cout<<endl;
        return ;
    }
    // 此行所有列
    for(int col = 0; col < 8; col++){
        // 第row行col列放置皇后
        if(isOk(result, row, col)){
            // 这一列找到位置,走到下一行去继续找
            result[row] = col;
            eightQueen(result, row + 1);
        }
    }
}


int main(int argc, char* argv[]){

    int result[8];
    memset(result, 127, sizeof(result));
    eightQueen(result, 0);

    return 0;
}
按照开头的算法框架的版本代码:
vector<vector<string>> res;

vector<vector<string>> solveNQueens(int n){
    // 初始化棋盘
    vector<string> board(n, string(n, '.'));
    backTrack(board, 0);
    return ans;
}

void backTrack(vector<string> &board, int row){
    // 触发结束条件
    if(row == board.size()){
        // 将路径加入到结果集中
        res.push_back(board);
        return ;
    }
    int cols = borad[row].size();
    for(int col = 0; col < cols; col++){
        // 判断选择是否合法
        if(isOk(row, col)){
            // 做选择
            board[row][col] = 'Q';
            // 进入下一层决策树
            backTrack(board, row + 1);
            // 撤销选择
            board[row][col] = '.';
        }
    }
}
原文地址:https://www.cnblogs.com/flyingrun/p/13476676.html