动态规划: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]);
    }
}
相关推荐
原野池予21 分钟前
深入Java集合框架:HashMap源码解析(JDK 8)
java·开发语言
古法安卓27 分钟前
Android-Direct Boot 阶段与 getFilesDir() 路径变更问题深度分析
android·java·android studio
-今昭-30 分钟前
Logstash 管理
java·服务器·前端
测试运维日常笔记31 分钟前
VMware vSphere、ESXi 与 vCenter Server:核心概念与关系详解
java·开发语言
Tyler_TXZ1 小时前
C++C语言之——树
c语言·c++·算法·
风流 少年1 小时前
Spring AI 2.0:Flux
java·人工智能·spring
m0_547486661 小时前
《面向对象与Java程序设计》全套PPT课件2026
java·开发语言
旖旎夜光1 小时前
LeetCode 30:串联所有单词的子串(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
白狐_7981 小时前
408 数据结构|完全二叉树两道典型题:第 6 层叶结点数与叶结点总数
数据结构·算法
lucas_AI1 小时前
喂张白纸也能吐出证件号?文档 MLLM 的"关系级泄露"被测出来了
人工智能·算法·掘金技术征文