39. Combination Sum-回溯法

原创 2016年08月29日 21:35:39

Tags: backTracking(回溯法)

   http://blog.csdn.net/jarvischu/article/details/16067319   

           http://www.cnblogs.com/chinazhangjie/archive/2010/10/22/1858410.html 

           http://blog.csdn.net/chinajane163/article/details/48969353

具有限界函数的深度优先生成法称为回溯法。(回溯法 = 穷举 + 剪枝)

回溯法按深度优先策略搜索问题的解空间树。首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。

        回溯法的基本行为是搜索,搜索过程使用剪枝函数来为了避免无效的搜索。剪枝函数包括两类:1. 使用约束函数,剪去不满足约束条件的路径;2.使用限界函数,剪去不能得到最优解的路径。

        问题的关键在于如何定义问题的解空间,转化成树(即解空间树)。解空间树分为两种:子集树和排列树。两种在算法结构和思路上大体相同。

       当问题是要求满足某种性质(约束条件)的所有解或最优解时,往往使用回溯法。

       它有“通用解题法”之美誉。

二. 回溯法实现 - 递归和递推(迭代)                               

        回溯法的实现方法有两种:递归和递推(也称迭代)。一般来说,一个问题两种方法都可以实现,只是在算法效率和设计复杂度上有区别。
      【类比于图深度遍历的递归实现和非递归(递推)实现】

1. 递归

        思路简单,设计容易,但效率低,其设计范式如下:

[cpp] view plain copy
  1. //针对N叉树的递归回溯方法  
  2. void backtrack (int t)  
  3. {  
  4. if (t>n) output(x); //叶子节点,输出结果,x是可行解  
  5. else  
  6. for i = 1 to k//当前节点的所有子节点  
  7. {  
  8. x[t]=value(i); //每个子节点的值赋值给x  
  9. //满足约束条件和限界条件  
  10. if (constraint(t)&&bound(t))   
  11. backtrack(t+1);  //递归下一层  
  12. }  
  13. } 

2. 递推

      算法设计相对复杂,但效率高。

[cpp] view plain copy
  1. //针对N叉树的迭代回溯方法  
  2. void iterativeBacktrack ()  
  3. {  
  4.     int t=1;  
  5.     while (t>0) {  
  6.         if(ExistSubNode(t)) //当前节点的存在子节点  
  7.         {  
  8.             for i = 1 to k  //遍历当前节点的所有子节点  
  9.             {  
  10.                 x[t]=value(i);//每个子节点的值赋值给x  
  11.                 if (constraint(t)&&bound(t))//满足约束条件和限界条件   
  12.                 {  
  13.                     //solution表示在节点t处得到了一个解  
  14.                     if (solution(t)) output(x);//得到问题的一个可行解,输出  
  15.                     else t++;//没有得到解,继续向下搜索  
  16.                 }  
  17.             }  
  18.         }  
  19.         else //不存在子节点,返回上一层  
  20.         {  
  21.             t--;  
  22.         }  
  23.     }  
  24. }  

三. 子集树和排列树                                                        

1. 子集树

       所给的问题是从n个元素的集合S中找出满足某种性质的子集时,相应的解空间成为子集树。
如0-1背包问题,从所给重量、价值不同的物品中挑选几个物品放入背包,使得在满足背包不超重的情况下,背包内物品价值最大。它的解空间就是一个典型的子集树。

       回溯法搜索子集树的算法范式如下:

[cpp] view plain copy
  1. void backtrack (int t)  
  2. {  
  3.   if (t>n) output(x);  
  4.     else  
  5.       for (int i=0;i<=1;i++) {  
  6.         x[t]=i;  
  7.         if (constraint(t)&&bound(t)) backtrack(t+1);  
  8.       }  
  9. }<span style="font-family:SimHei;">  
  10. </span>  

2. 排列树

      所给的问题是确定n个元素满足某种性质的排列时,相应的解空间就是排列树。
如旅行售货员问题,一个售货员把几个城市旅行一遍,要求走的路程最小。它的解就是几个城市的排列,解空间就是排列树。
      回溯法搜索排列树的算法范式如下:

[cpp] view plain copy
  1. <span style="font-size:18px;">void backtrack (int t)  
  2. {  
  3.   if (t>n) output(x);  
  4.     else  
  5.       for (int i=t;i<=n;i++) {  
  6.         swap(x[t], x[i]);  
  7.         if (constraint(t)&&bound(t)) backtrack(t+1);  
  8.         swap(x[t], x[i]);  
  9.       }  
  10. } </span><span style="font-family:SimHei;font-size:24px;">  
  11. </span>  

四. 经典问题                                    

(1)装载问题
(2)0-1背包问题
(3)旅行售货员问题
(4)八皇后问题
(5)迷宫问题
(6)图的m着色问题

本题的代码:

class Solution {
public:
	vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
		vector<vector<int>> res;
		vector<int> preCom;
		int size = candidates.size();
		backTracking(candidates, target, 0, preCom, res, size, 0);
		return res;
	}
	void backTracking(vector<int>& candidates, int target, int preSum, vector<int>& preCom, vector<vector<int>>& res, int& size, int ind){
		for (int i = ind; i < size; ++i){
			int tmp = preSum + candidates[i];
			if (tmp <= target){
				preCom.push_back(candidates[i]);
				if (tmp == target)
					res.push_back(preCom);
				if (tmp < target)
					backTracking(candidates, target, tmp, preCom, res, size, i);
				preCom.pop_back();
			}
		}
	}
};



[LeetCode - 回溯] 39. Combination Sum

1 问题 Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all u...

回溯详解及其应用:Leetcode 39 combination sum

原理 初入门 基本定义和概念 举栗子 编程思路 实践 生成符合规范的括号 combination sum n queen原理初入门有时会遇到这样一类题目,它的问题可以分解,但是又不能得出明确的动态规划...

深度优先搜索和回溯(实例LeetCode 39 Combination Sum)

搜索是广泛使用的算法策略,就是用问题的所有可能按照一定的顺序、规则去试探。它利用计算机的高性能来有目的的穷举一个问题的部分或所有可能情况,从而求出问题的解。而深度优先搜索是搜索算法中最简单最常见的。 ...

LeetCode 39. Combination Sum II

和LeetCode 38. Combination Sum

39-Combination Sum

题目:Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all uniqu...

leetcode【39+40+216+377 Combination Sum 相关】【python】

39Combination Sum是说让我们在给定数组C中找到所有的组合,使得组合中数字的和是target值。并且组合里的数字可以重复,也就是不限制C中每一个数字的使用。 这明显是回溯啦,大家记得让...

LeetCode39 Combination Sum

原题:英:Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all uni...

【一天一道LeetCode】#39. Combination Sum

一天一道LeetCode系列(一)题目 Given a set of candidate numbers (C) and a target number (T), find all unique ...

39. Combination Sum [leetcode][javascript解法]

Combination Sum Add to List QuestionEditorial Solution My Submissions Total Accepted: 128797 To...
  • dayuqi
  • dayuqi
  • 2016年12月13日 23:00
  • 149

LeetCode OJ-39-Combination Sum

题目:Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C w...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:39. Combination Sum-回溯法
举报原因:
原因补充:

(最多只允许输入30个字)