回溯法经典例题(一):java解01背包问题

经典例题

0-1背包问题

问题定义【来自百度百科

我们有n种物品,物品j的重量为wj,价格为pj。
我们假定所有物品的重量和价格都是非负的。背包所能承受的最大重量为c。
如果限定每种物品只能选择0个或1个,则问题称为0-1背包问题

实例描述

对于n=3的0-1背包问题, 物品的重量为w={16, 15, 15}, 物品的价值为p={45, 25, 25},背包承重最大值:C=30,求背包中能够装载的最大价值。

  1. 定义问题解空间;
    result=({0,0,0},{0,0,1},{0,1,0},{0,1,1},{1,0,0},{1,0,1},{1,1,0},{1,1,1}),共8种结果

  2. 确定易于搜索的解空间结构;
    该问题的解空间结构为子集树

0-1背包解空间结构
A代表第一件物品,0表示不把物品装进背包,1表示把物品装进背包

子集树概念:
当所给的问题是从包含n个元素的集合S中找出能满足某种性质的子集时,相应的解空间树称为子集树。例如,0-1背包问题的解空间树就是一棵子集树。这类子集树通常有2n个叶结点。遍历子集树的任何算法均需O(2的n次方)的计算时间

子集树代码框架如下:

void backtrack (int t)
{  if (t>n) output(x);
    else
      for (int i=0;i<=1;i++) {
        x[t]=i;
        if (legal(t)) backtrack(t+1);
      }
}
  1. 以深度优先方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。
    该问题的限界函数为
    在这里插入图片描述

代码实现
代码参考该博主,点击进入原博主博文,原博主写的很好!
以下仅做了在输出方面的修改

package KnapsackProblem;
public class _01KnapsackProblem {
	public int[] weight;
    public int[] value;
    public int[] take;
 
    int curWeight = 0;
    int curValue = 0;
 
    int bestValue = 0;
    int[] bestChoice;
    int count;
 
    int maxWeight = 0;
 
    public void init(int[] weight, int[] value, int maxWeight) {
        if (weight == null || weight.length == 0
                || value == null || value.length == 0
                || weight.length != value.length || maxWeight <= 0) {
            System.out.println("args wrong!");
            return;
        }
        this.value = value;
        this.weight = weight;
        this.maxWeight = maxWeight;
        count = value.length;
        take = new int[count];
        bestChoice = new int[count];
    }
 
    public int[] maxValue(int x) {
        //走到了叶子节点
        if (x > count - 1) {
            //更新最优解
            if (curValue > bestValue) {
                bestValue = curValue;
                for (int i = 0; i < take.length; i++) {
                    bestChoice[i] = take[i];
                }
            }
        } else {
            //遍历当前节点(物品)的子节点:0 不放入背包 1:放入背包
            for (int i = 0; i < 2; i++) {
                take[x] = i;
                if (i == 0) {
                    //不放入背包,接着往下走
                    maxValue(x + 1);
                } else {
                    //约束条件,如果小于背包容量
                    if (curWeight + weight[x] <= maxWeight) {
                        //更新当前重量和价值
                        curWeight += weight[x];
                        curValue += value[x];
                        //继续向下深入
                        maxValue(x + 1);
                        //回溯法重要步骤,个人感觉也是精华所在。
                        // 当从上一行代码maxValue出来后,需要回溯容量和值
                        curWeight -= weight[x];
                        curValue -= value[x];
                    }
                }
            }
        }
        return bestChoice;
    }
 
    public static void main(String[] args) {
    	_01KnapsackProblem bt=new _01KnapsackProblem();
        bt.init(new int[]{16,15,15},new int[]{45,25,25},30);
        int[] result = bt.maxValue(0);
        System.out.print("最佳选择为:[");
        for(int i=0;i<bt.bestChoice.length;i++) {
        	if(i==bt.bestChoice.length-1) {
        		System.out.print(bt.bestChoice[i]+"]");
        	}else {
            	System.out.print(bt.bestChoice[i]+","); 
        	}
        }
        System.out.print("\n此时价值最大,即"+bt.bestValue);
    }
}

  • 12
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
回溯法是一种常用的决问题的算法思想,它通过不断地尝试所有可能的决方案来找到问题的最优。而01背包问题一个经典的动态规划问题,它的目标是在给定的一组物品中选择一些物品放入背包中,使得物品的总价值最大,同时要求背包的容量不能超过一个给定的值。 在Java中,可以使用回溯法01背包问题。具体步骤如下: 1. 定义一个全局变量maxValue,用于记录当前找到的最大价值。 2. 定义一个递归函数backtrack,该函数用于尝试所有可能的决方案。 3. 在backtrack函数中,使用一个循环遍历所有物品,对于每个物品,有两种选择:放入背包或不放入背包。 4. 如果选择放入背包,则更新当前背包的容量和总价值,并递归调用backtrack函数继续尝试下一个物品。 5. 如果选择不放入背包,则直接递归调用backtrack函数继续尝试下一个物品。 6. 在每次递归调用结束后,需要将背包的容量和总价值恢复到递归前的状态,以便尝试其他可能的决方案。 7. 当遍历完所有物品后,比较当前的总价值与maxValue的大小,更新maxValue。 8. 最后返回maxValue作为最优。 下面是一个简单的Java代码示例: ```java public class Knapsack { private static int maxValue = 0; public static int solve(int[] weights, int[] values, int capacity) { backtrack(weights, values, capacity, 0, 0); return maxValue; } private static void backtrack(int[] weights, int[] values, int capacity, int index, int totalValue) { if (index == weights.length || capacity == 0) { maxValue = Math.max(maxValue, totalValue); return; } if (weights[index] <= capacity) { backtrack(weights, values, capacity - weights[index], index + 1, totalValue + values[index]); } backtrack(weights, values, capacity, index + 1, totalValue); } } ``` 使用示例: ```java public class Main { public static void main(String[] args) { int[] weights = {2, 3, 4, 5}; int[] values = {3, 4, 5, 6}; int capacity = 8; int maxValue = Knapsack.solve(weights, values, capacity); System.out.println("最大价值为:" + maxValue); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值