(十九)回溯法

 回溯法和DFS有区别

backtraking有一个诀窍 就是recursive call之后要退回到之前的一个状态。

基本思想

   在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。

       若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。

       而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。

解题一般步骤

    (1)针对所给问题,确定问题的解空间:首先应明确定义问题的解空间,问题的解空间应至少包含问题的一个(最优)解。

    (2)确定结点的扩展搜索规则

    (3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

一、排列组合问题

 public static  List<List<Integer>> permute(int[] nums) {
		 List<List<Integer>> res=new ArrayList<List<Integer>>();
		 ArrayList<Integer> al=new ArrayList<Integer>(); //存放路径上已经有的节点
		 boolean[] userd=new boolean[nums.length];
		 
		 //深度遍历,返回条件是没有可选的了,则返回,所以深入每层要看是否还有可选的
		 DFS(nums,res,al,userd);
		
		 for(int i=0;i<res.size();i++)
		 {
			 List<Integer> tmp=res.get(i);
			 for(int j=0;j<tmp.size();j++)
			 {
				 System.out.print(tmp.get(j)+",");
			 }
			 
			 System.out.println();
		 }
		 return null;
	    }
	 public static  void DFS(int[] nums,List<List<Integer>> res,ArrayList<Integer> al,boolean[] userd) {
		 
		 
		 if(al.size()==nums.length)
			 res.add((ArrayList<Integer> )al.clone());
		 
		 for(int i=0;i<nums.length;i++)
		 {
			 if(!userd[i])
			 {
				 userd[i]=true;
				 al.add(nums[i]);
				 DFS(nums,res,al,userd) ;
				 
				 //回复状态
				 al.remove(al.size()-1);
				 userd[i]=false;
			 }
		 }
	 }
	 
	 public static void main(String[] args) {
		 int[] nums={1,2,3};
		 permute(nums) ;
	}

注意点:①当回溯时,要恢复状态,可以简单举个例子就可以看出来怎么做

               ②深拷贝:

res.add(al):浅拷贝

 res.add((ArrayList<Integer> )al.clone());

 

 

posted @ 2019-07-15 20:37  测试开发分享站  阅读(163)  评论(0编辑  收藏  举报