动态规划算法——-背包问题

有一个背包,容量为一定值,现有不同可供选择的物品,每个物品有自己的重量属性和价值属性,要求:

  1. 目标为总价值最大,且重量不超出
  2. 装进背包的物品不重复

背包问题可分为01背包和完全背包(完全背包指的是每件物品都无限件可用。

思路分析:利用动态规划解决,每次遍历,对于给定的n个物品,设v[i]、w[i]分别为第i个物品的价值和容量,c为背包容量。

吉他 一磅 1500
音响 四磅 3000
电脑 三磅 2000

物品0磅1磅2磅3磅4磅
00000
吉他01500150015001500
音响01500150015003000
电脑01500150020003500
  • v[i][0] = v[0][j]=0 表中的第一行和第一列都等于0
  • 当w[i]>j的时候,也就是超出背包的容量了,所以要取上一次背包的容量。v[i][j] = v[i-1][j];
  • 当j>w[i]时,v[i][j] = max(v[i-1][j],v[i-1][j-w[i]] + v[i]),比较上一次背包能够装的value和背包总容量减去这一次装入的物品重量能够装入的最大值加上这次装入物品的value,取较大值。

以下代码为不需要记录背包存放情况而只需要value时的情况。

public class TestKnapsack {
    @Test
    public void test() {
        int []w = {1,4,3};//物品重量
        int []value = {1500,3000,2000};//物品的价值
        int m = 4;//背包容量
        int n = value.length;//物品的个数

        
        
        
        //创建二维数组=表

        //v[i][j]表示在前i个物品中能够装入j容量的最大值
        int [][]v = new int[n+1][m+1];

        //因为Java特性是已经把每个值赋值为0,则不用手动将第一行第一列设置为0
        for(int i = 1;i < n+1;i++) {
            for(int j = 1;j < m+1;j++) {
                if(w[i-1] > j ) {//因为从1开始,所以w数组下标要-1
                    v[i][j] = v[i-1][j];
                } else {
                    v[i][j] = Math.max(v[i-1][j],v[i-1][j-w[i-1]]+value[i-1]);//同理,value数组下标-1
                }
            }
        }
        System.out.println("在背包中能装入价值最大为" + v[3][4]);


    }
}

如果我们需要记录背包存放物品的情况,则需要再定义一个path的二维数组。

public class TestKnapsack {
    @Test
    public void test() {
        int []w = {1,4,3};//物品重量
        int []value = {1500,3000,2000};//物品的价值
        int m = 4;//背包容量
        int n = value.length;//物品的个数
        int [][]path = new int [n+1][m+1];



        //创建二维数组=表

        //v[i][j]表示在前i个物品中能够装入j容量的最大值
        int [][]v = new int[n+1][m+1];

        //因为Java特性是已经把每个值赋值为0,则不用手动将第一行第一列设置为0
        for(int i = 1;i < n+1;i++) {
            for(int j = 1;j < m+1;j++) {
                if(w[i-1] > j ) {//因为从1开始,所以w数组下标要-1
                    v[i][j] = v[i-1][j];
                } else {

                    //与之前代码不同的地方
                    v[i][j] = Math.max(v[i - 1][j], v[i - 1][j - w[i - 1]] + value[i - 1]);//同理,value数组下标-1
                    if(v[i-1][j] < v[i-1][j-w[i-1]]+value[i-1]) {

                        path[i][j] = 1;

                    }
                }
            }
        }
        //System.out.println("在背包中能装入价值最大为" + v[3][4]);
        int j = path[0].length-1;
        int i = path.length-1;

            while(i >0 && j>0) {
                if(path[i][j] == 1) {
                    System.out.printf("第%d个物品被放入背包",i);
                    j-=w[i-1];
                }
                i--;
            }


    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值