背包问题有许多种形式,最简单的背包问题形式:现在有一堆石头,(比如重量为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();
- }
- }