动态规划: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-vi j−vi 的选项集合

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

      • 变化的部分:包含前 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]);
    }
}
相关推荐
云烟成雨TD3 分钟前
Spring AI 1.x 系列【37】RAG 知识库平台案例:知识库管理
java·人工智能·spring
KANGBboy6 分钟前
java知识四(面向对象编程)
android·java·开发语言
tongluowan00713 分钟前
ThreadLocal,InheritableThreadLocal,TransmittableThreadLocal详解
java·多线程·上下文
qq_25183645742 分钟前
基于java Web 日化商超库存管理系统设计与实现
java·开发语言·前端
破土士V1 小时前
【Java基础语法10】继承、多态、抽象类接口、字符串与异常等
java·开发语言
轻刀快马1 小时前
撕开 Spring 的底裤:解析 Bean 生命周期与三级缓存的“破局”之术
java·spring·缓存
KobeSacre1 小时前
JVM ZGC
java·开发语言·jvm
Chase_______1 小时前
【Java基础 | 13】IO 流(下):缓冲流、转换流、序列化与综合案例
java·开发语言
bush41 小时前
嵌入式linux学习记录十二,mmap
java·linux·学习
嵌入式老牛2 小时前
液晶段码(米/日字格)识别—倾斜校正
opencv·算法·仿射变换