数据结构与算法(十四)背包问题及记录种类

问题描述:

一个容量为V的背包,现在有N件商品(相同的商品可以随意取为完全背包,最多只能取一次为01背包),每件商品的重量是w1,价值是v1,请问,这个背包所能容纳的最大价值是多少?

package algorithm;

public class KnapsackProblem {

    public static void main(String[] args) {
        int[] value = {1000, 3000, 5000, 3500};
        int[] weight = {1, 2, 4, 3};

        int capacity = 10;

        solution(capacity, weight, value);
        solution2(capacity, weight, value);


    }




    //01背包, 即每个物品最多被放入一次
    private static void solution(int capacity, int[] weight, int[] value) {
        //建立一个二维数组,列值为背包的容量,行值代表当前可选择的商品
        int[][] res = new int[weight.length + 1][capacity + 1];

        //res数组的第一行表示,没有商品可以选择,背包的价值应该为默认值0
        //res数组的第一列表示,背包的容量为0,所以背包的价值也为0

        for(int i = 1; i <= weight.length; i++ ){
            for (int j = 1; j <= capacity ; j++) {
                if(weight[i-1] > j){ //表示将要加入的物品重量大于当前背包的容量,即不能加入该商品
                    res[i][j] = res[i-1][j];
                }else{
                    //尝试将该商品加入到背包,这个时候背包中的总价值应该是该商品的价值加上背包剩余容量能装入的最大价值。
                    int tryValue = value[i - 1] + res[i-1][j-weight[i - 1]];
                    //将放入和不放入两种情况进行比较找到更优的解决方案
                    if(tryValue > res[i-1][j]){
                        res[i][j] = tryValue;
                    }else{
                        res[i][j] = res[i-1][j];
                    }
                }
            }
        }



        //打印res数组
        for (int i = 0; i< res.length; i++){
            for (int j = 0; j < res[0].length; j++) {
                System.out.print(res[i][j] + " ");
            }
            System.out.println();
        }

        //打印装入背包的策略,从大到小反向打印
        for (int i = res.length -1, j = res[0].length-1; i >0 && j >0 ; i--) {
            if(res[i][j] != res[i-1][j]){//说明第i件商品被选择,因为每件物品只能放置最多一件,直接减少物品种类,即i--
                System.out.printf("Put in %d good \n", i);
                j = j - weight[i-1];
            }
        }
    }

    //完全背包问题,即每个物品不限制放入的次数
    private static void solution2(int capacity, int[] weight, int[] value) {
        //建立一个二维数组,列值为背包的容量,行值代表当前可选择的商品
        int[][] res = new int[weight.length + 1][capacity + 1];

        //res数组的第一行表示,没有商品可以选择,背包的价值应该为默认值0
        //res数组的第一列表示,背包的容量为0,所以背包的价值也为0

        for(int i = 1; i <= weight.length; i++ ){
            for (int j = 1; j <= capacity ; j++) {
                //定义k, 表示尝试将第i个物品放入背包的次数
                for (int k = 0; k * weight[i - 1] <= j; k++) {
                    //尝试将该商品加入到背包k个时,背包的价值
                    int tryValue = value[i - 1] * k + res[i-1][j-weight[i - 1] * k];//当k=0时,相当于初始化res[i][j]的值等于res[i-1][j]
                    if (tryValue > res[i][j]){
                        res[i][j] = tryValue;
                    }
                }
            }
        }



        //打印res数组
        for (int i = 0; i< res.length; i++){
            for (int j = 0; j < res[0].length; j++) {
                System.out.print(res[i][j] + " ");
            }
            System.out.println();
        }

        //打印装入背包的策略,从大到小反向打印
        for (int i = res.length -1, j = res[0].length-1; i >0 && j >0 ; ) {
            if(res[i][j] != res[i-1][j]){//说明第i件商品被选择;将当前背包容量减少,继续比较是否放入该商品
                System.out.printf("Put in %d good \n", i);
                j = j - weight[i-1];
            }else {
                i = i - 1;
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值