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


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

    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] = '.';
            }
        }
    }
    
  • 相关阅读:
    UVA10763交换学生
    UVA10763交换学生
    UVA10391复合词
    UVA10391复合词
    UVA10125和集
    UVA10125和集
    POJ3762 时间段用k次
    POJ3762 时间段用k次
    Win64 驱动内核编程-11.回调监控进线程句柄操作
    Win64 驱动内核编程-11.回调监控进线程句柄操作
  • 原文地址:https://www.cnblogs.com/flyingrun/p/13476676.html
Copyright © 2020-2023  润新知