赞
踩
我们说过,回溯法虽然是暴力搜索,但也有时候可以有点剪枝优化一下的,主要就是去掉那些不必要的递归,从而提高执行效率。例如假如有五个男孩子都和一个女生说要厮守终生。她会和这五个人都先过一辈子再确定谁会真正做到吗?当然不会。而是会先思考一下,有一个可能导出勾勾搭搭,那她可以认为这个人只是一时兴起,剪掉!有一个可能太窝囊了,什么都不会,那她可以认为和他在一起会非常累,剪掉!有一个长得太对不起祖宗,可能会影响下一代,剪掉!最后就剩下两个,再进一步考虑!这就是剪枝!
在上一篇回溯的题目中,我们得遍历过程是这样的:
- for (int i = startIndex; i <= n; i++) {
- path.addLast(i);
- dfs(n, k, i + 1, path, res);
- }
这个遍历的范围是可以剪枝优化的,怎么优化呢?
来举一个例子,n = 4,k = 4的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。 在第二层for循环,从元素3开始的遍历都没有意义了。
图中每一个节点(图中为矩形),就代表本层的一个for循环,那么每一层的for循环从第二个数开始遍 历的话,都没有意义,都是无效遍历。所以,可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。
根据一个材料的说明,对于任何一次循环,已经选择的元素个数就是path.size(),还需要的元素个数为: k - path.size(),然后只要选择从开始到n - (k - path.size()) + 1就行了,但是我没太想明白为什么用这个。后面想清楚了再补充。
- public static void dfs(int n, int k, int startIndex, Deque<Integer> path, List<List<Integer>> res) {
- if (path.size() == k) {
- res.add(new ArrayList<>(path));
- return;
- }
- for (int i = startIndex; i <= n-(k-path.size())+1; i++) {
- path.addLast(i);
- dfs(n, k, i + 1, path, res);
- path.removeLast();
- }
- }
回溯的剪枝优化根据题目情况会有很多变化,这个只能具体问题具体分析了 。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。