当前位置:   article > 正文

递归与回溯5:剪枝优化

递归与回溯5:剪枝优化

我们说过,回溯法虽然是暴力搜索,但也有时候可以有点剪枝优化一下的,主要就是去掉那些不必要的递归,从而提高执行效率。例如假如有五个男孩子都和一个女生说要厮守终生。她会和这五个人都先过一辈子再确定谁会真正做到吗?当然不会。而是会先思考一下,有一个可能导出勾勾搭搭,那她可以认为这个人只是一时兴起,剪掉!有一个可能太窝囊了,什么都不会,那她可以认为和他在一起会非常累,剪掉!有一个长得太对不起祖宗,可能会影响下一代,剪掉!最后就剩下两个,再进一步考虑!这就是剪枝!
在上一篇回溯的题目中,我们得遍历过程是这样的:

  1. for (int i = startIndex; i <= n; i++) {
  2. path.addLast(i);
  3. dfs(n, k, i + 1, path, res);
  4. }

这个遍历的范围是可以剪枝优化的,怎么优化呢?
来举一个例子,n = 4,k = 4的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。 在第二层for循环,从元素3开始的遍历都没有意义了。

图中每一个节点(图中为矩形),就代表本层的一个for循环,那么每一层的for循环从第二个数开始遍 历的话,都没有意义,都是无效遍历。所以,可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。

根据一个材料的说明,对于任何一次循环,已经选择的元素个数就是path.size(),还需要的元素个数为: k - path.size(),然后只要选择从开始到n - (k - path.size()) + 1就行了,但是我没太想明白为什么用这个。后面想清楚了再补充。

  1. public static void dfs(int n, int k, int startIndex, Deque<Integer> path, List<List<Integer>> res) {
  2. if (path.size() == k) {
  3. res.add(new ArrayList<>(path));
  4. return;
  5. }
  6. for (int i = startIndex; i <= n-(k-path.size())+1; i++) {
  7. path.addLast(i);
  8. dfs(n, k, i + 1, path, res);
  9. path.removeLast();
  10. }
  11. }

回溯的剪枝优化根据题目情况会有很多变化,这个只能具体问题具体分析了 。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/434287
推荐阅读
相关标签
  

闽ICP备14008679号