动态规划之背包问题

文章介绍了背包问题,一种组合优化的NP完全问题,目标是选取物品以达到最高总价值但不超过限定总重量。文章提供了Java代码实现,通过回溯算法找出数组的所有子集,并在主函数中测试,寻找在背包最大容量限制下的最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背包问题

背包问题(Knapsack problem)是一种组合优化的NP完全问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。也可以将背包问题描述为决定性问题,即在总重量不超过W的前提下,总价值是否能达到V?了解回溯算法

数组的所有子集

/**
* 目标数组的所有子集
* @param array 数组对象
* @return 返回数组子集的集合对象
*/
public List<List<Integer>>  subsets(Integer[] array){
   // 创建存储子集的集合对象
   List<List<Integer>> list = new ArrayList<List<Integer>>();
   // 对数组进行排序
   Arrays.sort(array);
   // 调用回溯函数
   backStrack(list,new ArrayList<Integer>(),array,0);
   // 返回所有子集结果
   return list;
}

回溯算法求子集

/**
 * 回溯算法获得数组所有子集
 * @param list
 * @param arrayList
 * @param array
 * @param start
 */
private void backStrack(List<List<Integer>> list, List<Integer> arrayList, Integer[] array,int start) {

    // 将集合存储到执行集合中 public ArrayList(Collection<? extends E> c)
    list.add(new ArrayList<>(arrayList));

    // for循环添加
    for(int i = start; i < array.length ; i++){
        if(!arrayList.contains(array[i])){
            // 如果不存在就添加到集合中
            arrayList.add(array[i]);
            // 元素不可能一次性添加完,所以需要递归
            backStrack(list,arrayList,array,i+1);
            // 撤销选择,即就是撤销当前list中值,因为在前面已经将arrayList的值传走了
            arrayList.remove(arrayList.size()-1);
        }
    }
}

main测试

public static void main(String[] args) {
    // Weigh表示背包能承受的最大重量,maxKey表示最大价值,minWight表示每个子集的重量,temp临时变量,wight存储最大价值对应的重量
    Integer Weigh = 0,maxKey = 0,minWight = 0,temp = 0,wight = 0;
    // 存储最终的子集
    List<Integer> result = null;
    // map中键存储的是索引值,值存储的是重量
    Map<Integer,Integer> key = new HashMap<Integer,Integer>();
    // 创建键盘输入流
    Scanner input = new Scanner(System.in);
    System.out.println("背包的最大容量:");
    Weigh = input.nextInt();
    System.out.println("物品个数:");
    int index = input.nextInt();
    // map中索引值对应此处的价值
    Integer[] value = new Integer[index];
    for(int i = 0 ; i < index ; i++){
        System.out.print("物品"+(i+1)+"质量:");
        key.put(i,input.nextInt());
        System.out.print("物品"+(i+1)+"价值:");
        value[i] = input.nextInt();
    }
    Knapsack kp = new Knapsack();
    Integer[] array = key.keySet().toArray(new Integer[0]);
    List<List<Integer>> list = kp.subsets(array);
    for(List<Integer> l : list){
        minWight = 0;
        // 迭代器遍历map集合并计算其重量是否超过最大重量
        Iterator<Integer> iter = l.iterator();
        while(iter.hasNext())
            // 将该子集的所有重量相加
            minWight += key.get(iter.next());
        // 如果重量小于等于最大重量则,计算其价值
        if(minWight <= Weigh){
            // 初始化临时变量
            temp = 0;
            // 迭代器遍历子集,并通过数组索引计算其价值是否最大
            Iterator<Integer> it = l.iterator();
            while(it.hasNext())
                // 计算重量不超过最大重量子集中某个背包的价值
                temp += value[it.next()];
            // 如果当前背包的价值大于之前的,那么替换掉
            if(temp > maxKey) {
                // 记录当前的最大价值
                maxKey = temp;
                // 记录当前的重量
                wight = minWight;
                // 记录当前的集合
                result = l;
            }
        }
    }
    System.out.println("背包:"+result+" 最大价值为:"+maxKey+" 重量为:"+wight);
}

测试案例

案例:
 背包的最大容量:
 15
 物品个数:
 5
 物品1质量:2
 物品1价值:2
 物品2质量:12
 物品2价值:4
 物品3质量:1
 物品3价值:2
 物品4质量:1
 物品4价值:1
 物品5质量:4
 物品5价值:10
 背包:[0, 2, 3, 4] 最大价值为:15 重量为:8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值