回溯算法理论基础
代码模板
1 2 3 4 5 6 7 8 9
| void backtrack(int t) { if (t > n) output(x); else { for (int i = f(n, t); i <= g(n, t); i++) { x[t] = h(i); if (constraint(t) && bound(t)) backtrack(t + 1); } } }
|
回溯法解决的问题都可以抽象为树形结构,是的,我指的是所有回溯法的问题都可以抽象为树形结构!
因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度就构成了树的深度。
回溯法一般是在集合中递归搜索,集合的大小构成了树的宽度,递归的深度构成的树的深度。
大家可以从图中看出for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。
卡哥模板
1 2 3 4 5 6 7 8 9 10 11 12
| void backtracking(参数) { if (终止条件) { 存放结果; return; }
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) { 处理节点; backtracking(路径,选择列表); 回溯,撤销处理结果 } }
|
组合问题
每一层递归就是相当于一个for循环。
嵌套多少个for循环,就相当于递归多少次
经典错误,当时是我犯的错误
backtracking(n, k, startIndex + 1);
应该是i + 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class Solution { public: vector<int> path; vector<vector<int>> result; void backtracking(int n, int k, int startIndex){ if(path.size() == k) { result.push_back(path); return; }
for(int i = startIndex;i <= n;i++){ path.push_back(i); backtracking(n, k, startIndex + 1); path.pop_back(); } } vector<vector<int>> combine(int n, int k) { backtracking(n, k, 1); return result; } };
|
正确答案
i <= n - (k - path.size()) + 1
常见剪枝思路就是缩小i的范围
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class Solution { public: vector<int> path; vector<vector<int>> result; void backtracking(int n, int k, int startIndex){ if(path.size() == k) { result.push_back(path); return; }
for(int i = startIndex;i <= n;i++){ path.push_back(i); backtracking(n, k, i + 1); path.pop_back(); } } vector<vector<int>> combine(int n, int k) { backtracking(n, k, 1); return result; } };
|
剪枝操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class Solution { public: vector<int> path; vector<vector<int>> result; void backtracking(int n, int k, int startIndex){ if(path.size() == k) { result.push_back(path); return; }
for(int i = startIndex;i <= n - (k - path.size()) + 1;i++){ path.push_back(i); backtracking(n, k, i + 1); path.pop_back(); } } vector<vector<int>> combine(int n, int k) { backtracking(n, k, 1); return result; } };
|