01背包与完全背包的优化

目录

一、01背包

1. 01背包的空间优化

二、完全背包

1. 完全背包的时间优化

2. 完全背包的空间优化


一、01背包

1. 01背包的空间优化

import java.util.Scanner;

public class Knapsack_pro {
    /*
    01背包内存优化
        原理是这样
            如果我计算完dp[i],那么dp[i-1]就没什么用了,最后我的结果也只是在
            dp[n]行里面找到值

            当我计算完dp[i]行的时候第i-1行无用,剩下的是一个
            一维的数组
            所以我就可以,将dp二维数组直接变为一维数组
            dp继承的是自己的上一个dp[i-1][j],和[i-1][j-w[i]]的下标
            映射到一维数组中,取的就是自己这个位置上,和j-w[i]
            这样只需要一个一维数组,就可以解决问题

            需要注意的是,从i-1行更新到i的时候,需要重后往前遍历
            因为更新后面的值需要用到前面的值
            而且dp[0]也不用更新了,dp[0]一定是上一个的值
            j的循环范围应该是最大容量到自己本身的容量
     */
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int N = scan.nextInt();
        int V = scan.nextInt();
        int[] w = new int[N+1];
        int[] v = new int[N+1];

        for (int i = 1; i <= N; i++) {
            w[i] = scan.nextInt();
            v[i] = scan.nextInt();
        }


        int[] dp = new int[V+1];
        for(int i=1;i<=N;i++){
            for(int j = V;j>=w[i];j--){
                dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i]);
            }
        }

        System.out.print(dp[V]);
        scan.close();
    }


        /*
    模板
        首先
            N表示物品数量
            V表示背包容量
            w表示物品体积
            v表示物品价值
        01背包的优化版本和完全背包的优化版本很相似

        它的状态转移方程和完全背包一致
        dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i])
        只不过01背包用的是上一行的dp[j-w[i]],完全背包用的是这一行
        所以完全背包是要用优化后的前面的数字
        而01背包要用的是优化前的前面的数字
        所以完全背包从前往后遍历,01背包从后往前遍历


        i从1到N
        j从V到w[i]  (后面的没必要改)

        int N;
        int V;
        int[] w = new int[N+1];
        int[] v = new int[N+1];

        int[] dp = new int[N+1];

        for(int i= 1;i<=N;i++){
            for(int j=V;j>=w[i];j--){
                dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i]);
            }
        }
    */
}

二、完全背包

1. 完全背包的时间优化

/*
    完全背包时间优化版本
        上一个状态转移方程dp = Math.max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]
        展开
            dp[i][j] =
         |-     dp[i-1][j]
      max|      dp[i-1][j-w[i]]+v[i]
         |      dp[i-1][j-w[i]*2]+v[i]*2
         |      …………
         |-     dp[i-1][j-k*w[i]] + v[i]*k

            把j-w[i]代入j
            dp[i][j-w[i]] +v[i]
          |-    dp[i-1][j-w[i]] + v[i]
       max|     dp[i-1][j-w[i]*2]+v[i]*2
          |     …………
          |-    dp[i-1][j-k*w[i]] + v[i]*k

        所以dp[i][j] = Math.max(dp[i-1][j],dp[i][j-w[i]]+v[i])  区别在于01背包的方程是dp[i-1][j-w[i]]+v[i]  只能继承头上那个
                                                               而完全背包的   方程是 dp[i][j-w[i]]+v[i]   可以继承自己这一行的背包

       这两种状态,其实是一种都不放,和至少放一个
       可以继承自己这一行的原因是,就算再放一个第i种物品,那也是i种,但是01背包放完之后就没有了,所以继承不了自己这一行
     */


    /*
    核心代码
        KnapsackComplete
            初始化dp[0][0]
            for i(1,n)
                for j(0,c[i]-1)
                    dp[i][j] = dp[i-1][j] //容量不足以再放进一个i物品,所以只能继承上一个

                for j(c[i],m)
                    dp[i][j] = Math.max(dp[i-1][j],dp[i][j-c[i]]+w[i]) //这样后面的都可以继承同一行的前面的,接龙继承k次就算是规避掉循环了
     */

    /*
    // for(int i= 1;i<=N;i++){
        //     for(int j = 0;j<=V;j++){
        //         for(int k=0;k<=j/w[i];k++){
        //             dp[i][j] = Math.max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
        //         }
        //     }
        // }

        for(int i= 1;i<=N;i++){
            for(int j = 0;j<w[i];j++){
                dp[i][j] = dp[i-1][j];
            }
            for(int j=w[i];j<=V;j++){
                dp[i][j] = Math.max(dp[i-1][j],dp[i][j-w[i]]+v[i]);
            }
        }
     */

2. 完全背包的空间优化

/*
    完全背包空间优化
        上上一行的数据永远就没有用了,因为怎么继承都用不到他
        我们只关注上一行和这一行

        其实完全背包时间优化完成后,状态转移方程就已经和01背包很像了
        所以空间优化也很好想

        dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i])   此时的状态转移方程就和01背包完全一样了

        只不过,01背包优化后面的值需要用到上一行的前面的值,所以并不能一上来就把这一行的前面优化掉,这样上一行的数据就没有了

        完全背包用的是上一行的自己,还有这一行的j-w[i],所以完全背包就是要用优化完的前面的值

        所有01背包只能从后往前遍历
        完全背包可以从前往后遍历
     */


    /*
    模板
        首先
            N表示物品数量
            V表示背包容量
            w表示物品体积 大小是N+1
            v表示物品价值 大小是N+1
        就是上面这个
        i从物品的1到n
        j从第一个物品的重量开始向后继承,一直到继承到背包的容量
        dp[j]每次接龙前面的dp[j-w[i]]+v[i],和自己本身比较dp[j]也就是上一行的dp[i-1][j]只不过空间优化了

        int N;
        int V;
        int[] w = new int[N+1];
        int[] v = new int[N+1];

        int[] dp = new int[V+1];


        for(int i= 1;i<=N;i++){
            for(int j=w[i];j<=V;j++){
                dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i]);
            }
        }


        总结一下就是
        dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i]);
        i从1到N
        01背包j从V到w[i]
        完全背包j从w[i]到V
     */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值