LeetCode回溯(N皇后与解数独)

51 N皇后

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。

在这里插入图片描述

解法 回溯法

N皇后要注意两个皇后不能同时出现在同一行、同一列、同一左斜线和同一右斜线。同一行可在递归时完成记录,不需要额外的容器记录,同一列、左斜线和右斜线都是需要容器专门去记录,可以观察到斜线容器的长度为2 * n - 1
左斜线对应关系:row + col
右斜线对应关系:n - row + col - 1
如果if(col[i] || ldiag[row + i] || rdiag[total - row + i - 1])有一个为真,则说明该列、左斜线或者右斜线上存在一个皇后,则当前皇后一定无法放置在这个位置,就需要继续对下一列进行判断;
如果全为假,则说明当前皇后可以放置在这个地方,并把这一列、左斜线、右斜线位置设为true,防止其他皇后放入,进入下一轮的递归,直到所有皇后都找到了自己的放置位置!
附完整代码:

class Solution {
public:
    vector<vector<string>> ans;
    vector<string> res;
    bool solved;
    void backtrack(vector<bool>& col, vector<bool>& ldiag, vector<bool>& rdiag,  int total, int row){
        if(row == total){
            ans.push_back(res);
            return;
        }
        else{
            for(int i = 0; i < total; ++i){
                if(col[i] || ldiag[row + i] || rdiag[total - row + i - 1]){
                    continue;
                }
                //符合条件 放置皇后
                res[row][i] = 'Q';
                col[i] = ldiag[row + i] = rdiag[total - row + i - 1] = true;
                backtrack(col, ldiag, rdiag, total, row + 1);
                //回溯 拿走当前位置上的皇后
                col[i] = ldiag[row + i] = rdiag[total - row + i - 1] = false;
                res[row][i] = '.';
            }
        }
    }
    vector<vector<string>> solveNQueens(int n) {
        res.resize(n, string(n, '.'));
        vector<bool> col(n, false), ldiag(2 * n - 1, false), rdiag(2 * n - 1, false);
        solved = false;
        backtrack(col, ldiag, rdiag, n, 0);
        return ans;
    }
};

解数独

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则:

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

在这里插入图片描述
在这里插入图片描述

题解 回溯法

数独只有唯一解,可以设置一个标志,表示问题当前是否被解决,如果已经被解决就不需要在继续递归。
同样设置三个标志容器,分别用来检验行,列,三行三列组成的小块是否满足条件!与N皇后大同小异!
需要注意的可能是坐标到容器位置的一个映射关系:

class Solution {
public:
        bool row[9][9];
        bool col[9][9];
        bool block[9][9];
        bool solved;
        vector<pair<int, int>> vec;

    void dfs(vector<vector<char>>& board, int pos){
        if(pos == vec.size()){
            solved = true;
            return;
        }
        auto [i, j] = vec[pos];
        for(int digit = 0; digit < 9 && !solved; ++digit){
            if(!row[i][digit] && !col[j][digit] && !block[i / 3 * 3 + j / 3][digit]){
                board[i][j] = digit + '0' + 1;
                row[i][digit] = col[j][digit] = block[i / 3 * 3 + j / 3][digit] = true;
                dfs(board, pos + 1);
                row[i][digit] = col[j][digit] = block[i / 3 * 3 + j / 3][digit] = false;
            }
        }
    }

    void solveSudoku(vector<vector<char>>& board) {
        memset(row, false, sizeof(row));
        memset(col, false, sizeof(col));
        memset(block, false, sizeof(block));
        solved = false;
        for(int i = 0; i < 9; ++i){
            for(int j = 0; j < 9; ++j){
                if(board[i][j] == '.'){
                    vec.emplace_back(i, j);
                }
                else{
                    char num = board[i][j];
                    row[i][num - '1'] = col[j][num - '1'] =
                        block[i / 3 * 3 + j / 3][num - '1'] = true;
                }
            }
        }
        dfs(board, 0);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值