动态规划:01 背包(闫氏DP分析法)

动态规划:01 背包(闫氏DP分析法)

01 背包

www.acwing.com/problem/content/2/

DP:

  • 状态表示 f(i, j)

    • 集合:所有只考虑前 i i i 个物品,且总体积不超过 j j j 的选项的集合

    • 属性:max

      • 最终答案:f(N, V)
  • 状态计算:f(i, j) = max(f(i - 1, j), f(i - 1, j - v[i]) + w[i])

    • 选第 i i i 个物品:所有包含第 i i i 个物品的选项集合,其实需要找的就是变化的部分的最大值,即:从 1 1 1~ i − 1 i-1 i−1 中选择,且总体积小于等于 j − v [ i ] j-v[i] j−v[i] 的选项集合

      当 j < v [ i ] j < v[i] j<v[i] 时,该分支不存在

      • 变化的部分:包含前 i − 1 i-1 i−1 个物品的不同选项
      • 不变的部分:都需要包含第 i i i 个物品
    • 不选第 i i i 个物品:需要满足从 1 1 1~ i − 1 i-1 i−1 中选择,且总体积小于等于 j j j 的所有选项集合

二维朴素写法

java 复制代码
import java.util.*;

public class Main {
    static final int N = 1010;
    // f[i][j] 表示只对于前i个物品且使用j的背包空间,选取的所有方案中的最大值
    static int[][] f = new int[N][N];
    static int[] w = new int[N];
    static int[] v = new int[N];
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int V = sc.nextInt();
        
        for (int i = 1; i <= n; i++) {
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
        }
        
        // dp
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= V; j++) {
                if (j >= v[i]) {
                    // j >= v[i] 能够将第i个物品放入
                    // 放入第i个物品
                    f[i][j] = f[i - 1][j - v[i]] + w[i];
                }
                // 不放入第i个物品
                f[i][j] = Math.max(f[i][j], f[i - 1][j]);
            }
        }
        
        System.out.println(f[n][V]);
    }
}

一维优化写法

java 复制代码
import java.util.*;

public class Main {
    static final int N = 1010;
    // 一维优化,相当于每次的i直接覆盖在上一次的i-1数组上
    // 因为每一次只会用到上一层的,不会用到更上面的数据
    // 且每次j-v[i]只会用在j之前的,当使用从大到小遍历时,当前修改不会影响到后面的答案
    // 所以可以使用滚动数组优化
    static int[] f = new int[N];
    static int[] w = new int[N];
    static int[] v = new int[N];
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int V = sc.nextInt();
        
        for (int i = 1; i <= n; i++) {
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
        }
        
        // dp
        for (int i = 1; i <= n; i++) {
            // 想清楚为什么要从大到小
            // 因为遍历到j时要使用上一层的j-v[i],所以应当先遍历大的才能避免影响
            for (int j = V; j >= 0; j--) {
                if (j >= v[i]) {
                    // j >= v[i] 能够将第i个物品放入
                    // 不放入第i个物品, 放入第i个物品
                    f[j] = Math.max(f[j], f[j - v[i]] + w[i]);    
                }
            }
        }
        
        System.out.println(f[V]);
    }
}
相关推荐
秋说17 分钟前
【PTA数据结构 | C语言版】一元多项式求导
c语言·数据结构·算法
Maybyy30 分钟前
力扣61.旋转链表
算法·leetcode·链表
一只叫煤球的猫44 分钟前
【🤣离谱整活】我写了一篇程序员掉进 Java 异世界的短篇小说
java·后端·程序员
斐波娜娜1 小时前
Maven详解
java·开发语言·maven
Bug退退退1231 小时前
RabbitMQ 高级特性之事务
java·分布式·spring·rabbitmq
程序员秘密基地1 小时前
基于html,css,vue,vscode,idea,,java,springboot,mysql数据库,在线旅游,景点管理系统
java·spring boot·mysql·spring·web3
皮皮林5511 小时前
自从用了CheckStyle插件,代码写的越来越规范了....
java
小码氓1 小时前
Java填充Word模板
java·开发语言·spring·word
会飞的天明1 小时前
Java 导出word 实现饼状图导出--可编辑数据
java·word
Muxiyale1 小时前
使用spring发送邮件,部署ECS服务器
java·服务器·spring