0-1背包问题

笔者心得

0-1背包问题一直是笔者的心头大患,从第一次接触到现在做了三四遍了,愣是感觉有点不能熟练掌握,所有你大可不必因为一次做得难受而烦恼,大家都一样哦。😝
下面笔者力求用最简洁的语言与代码来解决这个问题。

解题思路

设共有len件物品,重量数组为weight[],价值容量为value[],背包容量为V(注意这里是大写的“V”)

先写表达式:

dp[i][v] = Math.max(dp[i-1][v],dp[i-1][v-weight[i-1]]+value[i-1]);

关于表达式

我们用dp[i][v]来表示将前i件物品装入容量为v(注意这里是小写的“v”)的背包所获得的最大价值,那么它可以由两个状态转移而来,其一是dp[i-1][v],表示没有装第i件物品,还有则是dp[i-1][v-weight[i]]+value[i],这里与上面表达式下标不同,只是因为使用了weight[0]与value[0]表示第一件物品,那么weight[i-]与value[i-1]则表示第i件物品。

上面表达式还有一点则是dp[i-1][v-weight[i]]+value[i],很多同学不理解数组后半部分为什么要用v-weight[i],只用v,即将前i物品装入容量为v的背包获得的价值=将前i-1件物品装入容量为v的背包可以获得的价值+物品i的价值。假设我们总共5件物品,只能装入容量为8的背包两件,而可以装入容量为6的背包一件,这显然是不等价的。

关于循环
for(int i=1;i<=len;i++) {
            for(int v=weight[i-1];v<=V;v++){...}
}

笔者一直对第二层循环很纠结,首先由于v表示容量,我们很少写这样的循环,这里由于容量都是整数,而且我们转移方程需要不同容量的背包,因此我们需要计算对于不同容量的背包装入前i件物品所获得的最大价值,当然这里v不能从1开始,因为我们的转移方程需要v-weight[i],而且将前1件物品装入容量需求比它所需要的容量更小的背包是不实际的。

附代码
public static void main(String[] args) {
        int weight[] = {3,5,1,2,2};
        int value[] = {4,5,2,1,3};
        
        int V =8;
        System.out.println(Bag_01(weight, value, V));
    //  System.out.println(Bag_01_2(weight, value, V));
    } 
    public static int Bag_01(int weight[],int value[],int V) {
        int len = weight.length;
        int res =0;
        int dp[][] = new int[len+1][V+1];
        for(int v=0;v<=V;v++) {
            //将前0件物品装入容量为v的背包所获得的最大价值
            dp[0][v] =0; 
        }
        
        for(int i=1;i<=len;i++) {
            for(int v=weight[i-1];v<=V;v++) {
                dp[i][v] = Math.max(dp[i-1][v],dp[i-1][v-weight[i-1]]+value[i-1]);
                
            }
            System.out.println("\n");
        }
        for(int i=1;i<=len;i++) {
            if(dp[i][V]>res)
                res = dp[i][V];
        }
        return res;
    }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。