01背包问题及优化思路

文章讲述了如何通过逆序迭代优化暴力动态规划算法,解决含有N件物品和容量限制的问题。原始的顺序更新会导致状态转移错误,而逆序则确保了从上一层正确地更新状态,从而实现价值的最大化。
摘要由CSDN通过智能技术生成

暴力做法

// 动态规划的具体含义 a[N][N] 当含有N件物品同时体积总容量为N的 价值为多少
import java.util.*;
public class Main{
    public static void main(String[] args){
        int n,m;
        int N = 1010;
        int[] v = new int[N];
        int[] w = new int[N];
        int[][] f = new int[N][N];
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        for(int i=1;i<=n;i++){
            v[i] = scan.nextInt();
            w[i] = scan.nextInt();
        }
        for(int i=1;i<=n;i++){
            for(int j=0;j<=m;j++){
                // 不拿第i个物品的情况
                f[i][j] = f[i-1][j];
                // 拿第i个物品的情况 但是前提需要满足当前的容量j要大于要取的物品的重量
                if(j >= v[i])
                f[i][j] = Math.max(f[i][j],f[i-1][j-v[i]]+w[i]);
            }
        }
        int res = 0;
        for(int i=1;i<=m;i++){
            res = Math.max(res,f[n][i]);
        }
        System.out.println(res);
    }
}

优化版本

import java.util.*;
public class Main{
    public static void main(String[] args){
        int n,m;
        int N = 1010;
        int[] v = new int[N];
        int[] w = new int[N];
        int[] f = new int[N];
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        for(int i=1;i<=n;i++){
            v[i] = scan.nextInt();
            w[i] = scan.nextInt();
        }
        for(int i=1;i<=n;i++){
            for(int j=m;j>=v[i];j--){
                f[j] = Math.max(f[j],f[j-v[i]]+w[i]);
            }
        }
        int res = 0;
        for(int i=1;i<=m;i++){
            res = Math.max(res,f[i]);
        }
        System.out.println(res);
    }
}

为何能进行这样的优化?

由原来的状态转移方程:

f[i][j] = f[i-1][j] // 在不取i的情况下 转移到上一个状态
// ……两重循环……
f[i][j] = Math.max(f[i][j],f[i-v[i]] + w[i]); // 取得i的情况下 根刚才的不取情况中选择最大值

所以,对于总容量为j的情况下,f[i][j]的状态实际是由上一层的i-1状态更新过来。

为何按照原来的正序就不能达到这样的效果?

当从小到大正序更新的时候,不妨进行举例:

// 取i=10 j=15
f[15] = Math.max(f[15],f[15-v[10]]+w[10]);

而在这里面,v[10]一定是一个非负数,15-v[10]严格小于等于15,因此在这里计算状态转移的时候,是由第i层转移,而不是朴素算法想要达到的从i-1层开始转移。所以正序是不行的。

为何逆序就可以达到这样的效果?

同等上一个例子,15-v[10]严格小于等于15,由于是从大向小迭代,在第i层更小的状态还没有计算,所以只能找到之前i-1层的状态,实现了朴素算法要达到的效果。done

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值