递归-背包问题

背包问题有许多种形式,最简单的背包问题形式:现在有一堆石头,(比如重量为2,6,8,10),一个背包中可以装指定的重量(比如14)的石头,请问背包中可以放入的石头的组合。

代码中假设石头是个源数组,背包是目标数组。

算法中使用分治的想法将此问题递归为两个小范围的问题。

针对第n个石头,背包问题可以分解为两种组合的何:含第n个石头的背包的组合,与不含n个石头的背包的组合,

1.假设含第n个石头,背包问题变为,针对剩下的石头求得总重量减去第n个石头的重量的背包问题。

2.不含n个石头,背包问题变为针对剩下的石头求得总重量的背包问题。

class Bag {
	public static void main(String[] args) {
		int[] src = {2,4,5,7,8,6,10};
		select(14,src, 0, new int[src.length]);
	}
	
	/**
	 * @param total 总数
	 * @param src 源数据数组
	 * @param offset 源数组的起始位置
	 * @param bag 背包,装选中的数据
	 */
	private static void select(int total, int [] src, int offset, int[] bag) {
		if(total == 0) {	//背包要求增加的重量为0,则直接打印背包
			print(bag);
			return;
		}
		//从起始值开始寻找第一个小于要求增加重量的数值
		while(offset < src.length && total < src[offset]) offset++;
		if(offset >= src.length) return;	//当没有源数据可以选择,则退出
		//将问题化简为在剩下的源数据中,两个找到重量的问题
		select(total,src,offset+1,bag.clone());	//背包中不含有offset位置的
		select(total-src[offset],src,offset+1,put(bag,src[offset]));//背包中含有offset位置的
	}
	
	private static int[] put(int[] bag, int n) { //将数字放入背包中
		int pos = -1;
		while(bag[++pos] > 0);	//找到背包中第一个数字为0的位置
		bag[pos] = n;
		return bag;
	}

	private static void print(int[] bag) {	//打印背包中的数字
		System.out.print("bag: ");
		for(int n: bag) {
			if(n == 0) break;
			System.out.print(n + " ");
		}
		System.out.println();
	}
}
 

你可能感兴趣的:(algorithm,算法)