动态规划之背包问题

目录

一、01背包

二、完全背包


一、01背包

描述:给定n个重量为w1,w2,w3.……Wn,价值为v1,v2,v3...Vn的物品和容量为C的背包,求这个物品中一个最有价值的子集,使得在满足背包的容量的前提下,包内的总价值最大。

01-背包:每个物品只能使用0次或1次。

package algorithm;

/**
 * @ClassName Bag01
 * Description 01背包
 * @Auther 青青子衿
 * @Date 2019/5/10 17:17
 */
public class Bag01 {
    public static int Bag(int[] w, int[] v, int C) {
        int size = w.length;
        if (size == 0) {
            return 0;
        }
        int[][] dp = new int[size][C+1];
        //初始化第一行
        //仅考虑容量为C的背包放第0个物品的情况
        for (int i = 0; i <= C;i++) {
            dp[0][i] = w[0]<=i? v[0]:0;
        }
        //下面外层for循环是依次放第1个物品~第size-1个物品的情况
        //内层for循环是依次存储背包容量为0~C情况下能最大放的物品价值
        for (int i = 1; i < size; i++) {
            for (int j = 0; j <= C; j++) {
                //要先保存上一行的值,不然直接max比较的话,有些情况可能为0
                dp[i][j] = dp[i-1][j];  //这个地方一定要注意!!!
                if (w[i] <= j) {   //前提是能放得下,才考虑是放还是不放
                    dp[i][j] = Math.max(dp[i][j] ,dp[i-1][j-w[i]]+v[i]);
                }
            }
        }
        //完全是为了打印-让结果更清晰
        for (int i = 0; i < size; i++) {
            for (int j = 1; j <= C; j++) {
                System.out.print(dp[i][j]+" ");
            }
            System.out.println();
        }
        return dp[size-1][C];
    }
    public static void main(String[] args) {
        int[] w = {2, 1, 3, 2};
        int[] v = {12, 10, 20, 15};
        System.out.println(Bag(w, v, 5));

    }
}

运行结果(看得更详细一点儿):

运行结果详解
dp[i][j]背包容量为1背包容量为2背包容量为3背包容量为4背包容量为5
第1个物品012121212
第2个物品1012222222
第3个物品1012223032
第4个物品1015253037
最后输出结果:
37

二、完全背包

完全背包问题是决策时对于每个物品,可以选择多次,只要背包还能装得下!01背包是规定每个物品只能选择一次。

01背包在选第i个物品时,背包容量够用的情况下,有2种状态可选:放or不放,找出最大价值的选择。

完全背包在选第i种物品时,背包容积够用的情况下,有多种状态可选,放0个(即不选),放1个,放2个,放3个……上限是放到背包放不下为止!找出最大价值的选择。

k = j/w[i]算出最多可以放几个。j是当前背包剩余容量,w[i]是当前物品重量。

代码见下(根据01背包稍作修改即可使用):

public class CompleteBag {

    public static int bag(int[] w, int[] v, int C) {
        int length = w.length;
        int[][] dp = new int[length][C+1];
        for (int i = 0; i <= C; i++) {
            //在背包容量允许的情况下,为了最大价值,放入i / w[0]个v[0]物品
            dp[0][i] = i / w[0] * v[0];  //放第一行也很重要,这个地方要做修改,要注意!!!!
        }
        int max =0;
        for (int i = 1; i < length; i++) {
            for (int j = 0; j <= C; j++) {
                for (int k = 0; k <= j / w[i]; k++) {
                    int temp = dp[i-1][j-k*w[i]]+k*v[i];
                    if(max<temp){//遍历选择放入k个物品可以得到的价值最大
                        max = temp;
                    }
                }
                dp[i][j] = max;
                max =0;
            }
        }
        //为了结果更清晰,打印数组信息
        for (int i = 0; i < length; i++) {
            for (int j = 1; j <= C; j++) {
                System.out.print(dp[i][j]+" ");
            }
            System.out.println();
        }
        return dp[length-1][C];
    }

    public static void main(String[] args){
        int[] w = {1,2,3,4,5,6,7,8};
        int[] v = {1, 5, 8, 9, 10, 17, 17, 20};
        System.out.println(bag(w,v,8));
    }
}

运行结果:

1 2 3 4 5 6 7 8 
1 5 6 10 11 15 16 20 
1 5 8 10 13 16 18 21 
1 5 8 10 13 16 18 21 
1 5 8 10 13 16 18 21 
1 5 8 10 13 17 18 22 
1 5 8 10 13 17 18 22 
1 5 8 10 13 17 18 22 
22

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值