16 排列型回溯

157 阅读1分钟

灵神【基础算法精讲】视频的个人笔记。

视频例题

46.全排列

image.png

组合无顺序。从1,2,3中选两个

flowchart TB
	1 --> 1,2 & 1,3
	2 --> 2,3

在1时,选比1大的2和3。在2时,选比2大的3,不需要再选1,2,1跟1,2一样,重复了。

//一个循环即可,下一个数 选比当前数大的数
for(int j = i; j < 3; ++j) //i为当前选的数

但是全排列有顺序。从1,2,3中选两个

flowchart TB
	1 --> 1,2 & 1,3
	2 --> 2,1 & 2,3 

在2时,仍然要选1,与2的大小无关。这时就需要一个布尔数组on_path,表示是否已经选过(在路径上)。

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> path, nums;
    vector<bool> on_path;
    int n;
    
    void dfs(int i) {
        if(i >= n) {
            ans.emplace_back(path);
            return;
        }

        for (int j = 0; j < n; ++j) {
            if(on_path[j]) continue; //已在path上
            
            path.emplace_back(nums[j]);
            on_path[j] = true;
            dfs(i + 1);
            path.pop_back(); //恢复
            on_path[j] = false;
        }
            
    }

    vector<vector<int>> permute(vector<int>& _nums) {
        nums = _nums;
        n = _nums.size();
        vector<bool> on(n, false);
        on_path = on;
        dfs(0);
        return ans;
    }
};

51.N 皇后

image.png

三个条件

  • 不能同一行
    • 那么每次在一行中选一个皇后就行了。
  • 不能同一列
    • on_path记录该列是否已选。
  • 不能同一斜线上
    • x + y x - y相等时,两点在同一条线上,记录这两是否已选即可。
    • diag1记录x + y
    • diag2记录 x - y

问题转换成多个子问题:

  • 原问题:选n个皇后。
  • 子问题:在第row行选一个皇后。
class Solution {
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<vector<string>> ans;
        vector<int> cols(n), on_path(n), diag1(n * 2 - 1), diag2(n * 2 - 1);

        function<void(int)> dfs = [&](int row) {
            if(row >= n) {
                vector<string> t(n);
                for (int i = 0; i < n; ++i) //".Q.."
                    t[i] = string(cols[i], '.') + 'Q' + string(n - cols[i] - 1, '.');  
                ans.emplace_back(t);
                return;
            }

            for (int col = 0; col < n; ++col) { //枚举列
                int rc = row - col + n - 1; // +n-1 变回正数
                if(on_path[col] || diag1[row + col] || diag2[rc]) continue; //该列已选 或 在一条斜线上
 
                cols[row] = col;
                on_path[col] = diag1[row + col] = diag2[rc] = true;
                dfs(row + 1); //这一行选完了,下一行
                on_path[col] = diag1[row + col] = diag2[rc] = false; //恢复
            }
        };

        dfs(0);
        return ans;
    }
};