dfs(爆搜) 和 全排列
dfs递归
图解
- 递归就是把一个大问题变成中问题再变成一个很小的问题进行解决
- 如果在分解问题时,可能出现一个大问题包括很多个中问题的情况,此时就要在递归外面加上for循环
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| int n; int path[N]; int st[N];
void dfs(int u){ if(u>n){ for(int i=1;i<=n;i++){ cout << path[i] << " "; } cout << "\n"; } for(int i=1;i<=n;i++){ if(!st[i]){ path[u] = i; st[i] = 1; dfs(u+1);
st[i] = 0; } } }
int main(){ cin >> n; dfs(1); return 0; }
|
next_permutation() 函数
全排列函数 next_permutation(num,num+n) 是对数组num中的前n个元素进行全排列,同时并改变num数组的值。
另外,需要强调的是,next_permutation()在使用前需要对欲排列数组按升序排序(此时才能找全),否则只能找出该序列之后的全排列数
next_permutation(node,node+n,cmp)可以对结构体num按照自定义的排序方式cmp进行排序
常用方式:
1 2 3 4
| do{
}while(next_permutation(a,a+n));
|
dfs例题:
飞机降落问题
使用全排列函数对所有情况进行枚举,判断在所有的情况下是否能够满足条件。
使用方式:
- 初始化一个全排列数组 a[n] ,通过a[i] = i对其赋值(初始时其为1,2,…,n)
- 下面每种情况其循环时的下标应当为 a[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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n,m; int flag;
struct node{ int t,d,l; }p[N];
int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> m; while(m--){ cin >> n; int a[n]; for(int i=1;i<=n;i++) a[i] = i; for(int i=1;i<=n;i++) cin >> p[i].t >> p[i].d >> p[i].l; do{ flag = true; int start = 0; for(int i=1;i<=n;i++){ int j = a[i];
start = max(start , p[j].t) ; if(p[j].t + p[j].d >= start){ start += p[j].l; } else{ flag = false; break; } } if(flag){ cout << "YES" << "\n"; break; } }while(next_permutation(a+1,a+n+1)); if(!flag) cout << "NO" << "\n"; } return 0; }
|
组合问题
组合
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Solution { public: vector<vector<int>> res; vector<int> path; void dfs(int n,int k,int startIndex){ if(path.size() == k){ res.push_back(path); return; } else{ for(int i=startIndex;i<=n;i++){ path.push_back(i); dfs(n,k,i+1); path.pop_back(); } } } vector<vector<int>> combine(int n, int k) { dfs(n,k,1); return res; } };
|
组合总和
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
和普通组合问题的区别
- 组合中的元素个数没有数量要求
- 元素可无限重复选取
startIndex 不需要在 ++
原始组合问题:backtracking(candidates, target, sum, i+1);
本题的递归回溯:backtracking(candidates, target, sum, i);
在求和问题中,排序之后加剪枝是常见的套路!
排列问题
和组合问题的区别
- 每层都是从0开始搜索而不是startIndex
- 需要used数组记录path里都放了哪些元素了