回溯法实现求解子集合和问题

瘦欲@ 提交于 2019-11-30 16:44:00

1.回溯法简介

  回溯法是一种在解空间搜索问题的解的方法。它在问题的解空间树种,按深度优先的策略,从根节点出发搜索解空间树。算法搜索至解空间树的任一节点时,先判断该节点是否包含问题的解。如果不包含,则跳过对以该节点为根的子树的搜索,逐层向其祖先节点回溯,否则进入该子树,继续按深度优先策略搜索。用回溯法求解问题的所有解的时,要回溯到根,且根节点的所有子树都被搜索遍才结束。用回溯法求问题的一个解时,只要搜索到问题的一个解就可以结束了,这种以深度优先方式系统搜索问题解的算法称为回溯法。

2.子集合和问题

  

3.代码

package depth.first.search;

import java.util.Scanner;
import java.util.Stack;
/***
 * 用深度优先算法求一个数组的子数组的和是否能达到某个值
 * 回溯法
 * @author admin
 *
 */
public class Subarray {

	public static void main(String[] args) {
		int n;
		Scanner in = new Scanner(System.in);
		n = in.nextInt();
		int[] array = new int[n];
		for (int i = 0; i < array.length; i++) {
			array[i] = in.nextInt();
		}
		//深度优先使用的数据结构
		Stack<Integer> s = new Stack<Integer>();
		//记录当前回溯的位置
		Stack<Integer> s1 = new Stack<Integer>();
		int sum = 0;
		int k = 0,j = 0;
		boolean judge = false;
		while(k<n){
			//约束条件
			if(array[k]>9){
				k++;
				continue;
			}
			s.push(array[k]);
			s1.push(k);
			sum = array[k];
			j = k+1;
			if(sum==9){
				judge  = true;
				break;
			}
			while(!s.isEmpty() && j<n){
				if(array[j]>9){
					j++;
					if(j==n){
						sum = sum - s.pop();//弹出时应该减去那个值
						j = s1.pop()+1;
					}
					continue;
				}
				sum = sum + array[j];
				if(sum==9){//找到结束
					s.push(array[j]);
					s1.push(j);
					judge = true;
					break;
				}else if(sum > 9){//太大,不压入栈
					sum = sum - array[j];
				}else{
					s.push(array[j]);
					s1.push(j);
				}
				j++;
				if(j==n){
					sum = sum - s.pop();//弹出时应该减去那个值
					j = s1.pop()+1;
				}
			}
			if(judge){
				break;
			}
			k++;
		}
		
		if(judge){
			for (Integer integer : s) {
				System.out.print(integer+" ");
			}
		}else{
			System.out.println("找不到这样的子数组");
		}
	}
	
}

非递归实现:
package depth.first.search;

import java.util.Scanner;
import java.util.prefs.BackingStoreException;

public class RecursiveSubArray {

	private int add = 0;
	//子数组的和
	private int sum = 0;
	private boolean judge = false;
	public static void main(String[] args) {
		int n;
		Scanner in = new Scanner(System.in);
		n = in.nextInt();
		//对应的集合
		int[] array = new int[n];
		for (int i = 0; i < array.length; i++) {
			array[i] = in.nextInt();
		}
		//用来记录哪个元素被选用
		int[] record = new int[n];
		RecursiveSubArray r =  new RecursiveSubArray();
		//子集合和为9
		r.sum = 9;
		r.backtrack(0, array, record);
		if(r.judge){
			for (int i = 0; i < n; i++) {
				if(record[i]==1){
					System.out.print(array[i]+" ");
				}
			}
		}
	}

	//回溯法
	public boolean backtrack(int t,int[] array,int[] record){
		if(t<array.length){
			add = add + array[t];
			if(add==sum){
				record[t] = 1;
				judge = true;
				return judge;
			}else if(add > sum){
				add = add - array[t];
				if(backtrack(t+1, array, record)){
					return true;
				}
				
			}else{
				record[t] = 1;//选择该元素
				if(backtrack(t+1, array, record)){
					return true;
				}else{
					record[t] = 0;//不选该元素
					add = add - array[t];
					if(backtrack(t+1, array, record)){
						return true;
					}
				}
			}
		}
		return false;
		
	}
}


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!