回溯算法

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


public class ConbinnationSum {
    List<List<Integer>> ll=new ArrayList<List<Integer>>();
    public static void main(String[] args) {
        int[] c={10,1,2,7,6,1,5};
        new ConbinnationSum().combinationSum(c, 8);
//        ArrayList<Integer> l=new ArrayList<Integer>();
//        new ConbinnationSum().testNode(3,l,0,7,c);
    }
public  List<List<Integer>> combinationSum(int[] candidates, int target) {
        int sum=0;
        ArrayList<Integer> l=new ArrayList<Integer>();
//        List<List<Integer>> ll=new ArrayList<List<Integer>>();
        Arrays.sort(candidates);
        
        for(int i=0;i<candidates.length && candidates[i]<=target;i++){
            testNode(i,l,sum,target,candidates);
        }
        System.out.print(ll.toString());
        return ll;
    }

 void testNode(int i, ArrayList<Integer> l, int sum, int target,int[] candidates) {
    // TODO Auto-generated method stub
    if(sum==target){
        if(!ll.contains(new ArrayList<Integer>(l))){
            
            ll.add(new ArrayList<Integer>(l));
           //这里注意 一定要用l新建一个List对象 而不能直接ll.add(l);
//            因为List<List<Integer>> 中存的是 List<Integer>对象的存储地址  直接ll.add(l) 这样ll 中存的全部是l这一个地址,
//            比如添加5次l,虽然添加的时候l中存的内容不一样 但最后ll中存的都是5个相同的值,这个值是最终l的内容
        }
//        l.remove(l.size()-1);
    }
//    sum+=candidates[i];
    if(sum>target||i>candidates.length){
//        sum=sum-candidates[i];
//        l.remove(new Integer(candidates[i]));
    }else{
        l.add(candidates[i]);
        sum+=candidates[i];
        int n=l.size();
        int j=i+1;
        do{
            testNode(j,l,sum,target,candidates);
            j++;
        }while(j<candidates.length&&candidates[j]<=target);
//        for(int j=i+1;j<candidates.length&&candidates[j]<=target;j++){//注意 for循环 对i的处置也要进行条件判断 不符合条件 直接跳过循环内容
//            testNode(j,l,sum,target,candidates);
//        }
        l.remove(new Integer(candidates[i]));
        sum=sum-candidates[i];
        
    }
}

}

public List<List<Integer>> combinationSum(int[] nums, int target) {
    List<List<Integer>> list = new ArrayList<>();
    Arrays.sort(nums);
    backtrack(list, new ArrayList<>(), nums, target, 0);
    return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int remain, int start){
    if(remain < 0) return;
    else if(remain == 0) list.add(new ArrayList<>(tempList));
    else{ 
        for(int i = start; i < nums.length; i++){
            tempList.add(nums[i]);
            backtrack(list, tempList, nums, remain - nums[i], i); // not i + 1 because we can reuse same elements
            tempList.remove(tempList.size() - 1);
        }
    }
}


回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就剪枝“回溯”返回,尝试别的路径。首先最重要的是针对所给问题,确定问题的树形(图形)解空间,然后以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。一般用递归的方法实现回溯算法:给出一个回溯递归函数的框架,

递归函数的函数功能可理解为 在当前情况下负责搜索 t节点为根的子树 所需要进行的操作。如上面Conbination Sum问题中 的递归函数testNode(int i, ArrayList<Integer> l, int sum, int target,int[] candidates)就是 在 之前累积的和 为sum  临时选择的整数子集为l 时遇到 节点i 时所需做的操作:判断是不是之前的情况已满足要求(及sum是否等于target),满足就输出 子集l ,判断sum是否大于target 大于的话就将通向i的这支减掉,小于的话说明 可以将 i 加入l  并搜索i下面的子树 (for循环) 记得在搜索完其子树后要 恢复 l 和 sum(l.remove(new Integer(candidates[i])); sum=sum-candidates[i];)。

backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int remain, int start)
这个递归函数 处理的情况是 面对 start节点已经加入子集 后的搜索。


回溯法对解空间作深度优先搜索,因此,在一般情况下用递归方法实现回溯法。

// 针对N叉树的递归回溯方法

void backtrack (int t)

{

    if (t > n) {

       // 到达叶子结点,将结果输出

       output (x);

    }

    else {

       // 遍历结点t的所有子结点

       for (int i = f(n,t); i <= g(n,t); i ++ ) {

           x[t] = h[i];

           // 如果不满足剪枝条件,则继续遍历

           if (constraint (t) && bound (t)) 

              backtrack (t + 1);

       }

    }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值