当前位置: 首页 > news >正文

笔记:背包问题总结

1. 01 背包(每种物品只能选一次)

思路:

  • 每个物品只能取 0 次或 1 次,求在容量限制内的最大价值。

  • 定义 dp[j] 表示容量 j 时的最大价值。

  • 遍历物品,从后向前遍历容量,防止物品被重复使用。

  • 状态转移方程: dp[j] = max(dp[j], dp[j - w[i]] + v[i])

代码模板:

for (int i = 0; i < N; i++) {  // 遍历物品
    for (int j = V; j >= w[i]; j--) {  // 倒序遍历背包容量
        dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
    }
}

示例: 输入:

3 5
2 3
1 2
3 4

计算过程:

  1. 初始化 dp = [0, 0, 0, 0, 0, 0]

  2. 处理第一个物品(重量2,价值3):

    • dp[5] = max(dp[5], dp[3] + 3) = 3

    • dp[4] = max(dp[4], dp[2] + 3) = 3

    • dp[3] = max(dp[3], dp[1] + 3) = 3

    • dp[2] = max(dp[2], dp[0] + 3) = 3

  3. 处理第二个物品(重量1,价值2),依次更新。

  4. 处理第三个物品(重量3,价值4),依次更新。

最终 dp[5] = 5


2. 完全背包(每种物品可以选无限次)

思路:

  • 每个物品可以取无限次。

  • 仍然定义 dp[j],但这次要正序遍历容量。

  • 状态转移方程: dp[j] = max(dp[j], dp[j - w[i]] + v[i])

代码模板:

for (int i = 0; i < N; i++) {  // 遍历物品
    for (int j = w[i]; j <= V; j++) {  // 正序遍历背包容量
        dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
    }
}

示例: 输入:

2 4
1 2
2 4

计算过程:

  1. 初始化 dp = [0, 0, 0, 0, 0]

  2. 处理第一个物品(重量1,价值2):

    • dp[1] = 2, dp[2] = 4, dp[3] = 6, dp[4] = 8

  3. 处理第二个物品(重量2,价值4):

    • dp[2] = 4(不变),dp[3] = 6(不变),dp[4] = 8(不变)

最终 dp[4] = 8


3. 多重背包(每种物品最多选 Si 次)

思路:

  • 直接按照 01 背包 方式处理的时间复杂度较高。

  • 使用 二进制拆分优化,将 s[i] 个物品拆分成若干个 2^k 份,使得 2^0 + 2^1 + ... 覆盖 s[i]

  • 状态转移方程: dp[j] = max(dp[j], dp[j - k * w[i]] + k * v[i])

代码模板(使用二进制优化):

for (int i = 0; i < N; i++) {  // 遍历物品
    int count = s[i];
    for (int k = 1; count > 0; k *= 2) {  // 二进制拆分
        int num = Math.min(k, count);
        count -= num;
        int weight = num * w[i];
        int value = num * v[i];
        for (int j = V; j >= weight; j--) {  // 01 背包处理
            dp[j] = Math.max(dp[j], dp[j - weight] + value);
        }
    }
}

示例: 输入:

3 10
2 3 3
3 4 2
5 6 2

计算过程(使用二进制优化拆分):

  1. 物品1(重量2,价值3,最多选3次)拆分成 1, 2

    • dp[10] = max(dp[10], dp[8] + 3)

    • dp[8] = max(dp[8], dp[6] + 3)

    • 依次更新 dp[2] = 3, dp[4] = 6, dp[6] = 9

  2. 物品2(重量3,价值4,最多选2次)拆分成 1, 1

    • 依次更新 dp[3] = 4, dp[6] = 8, dp[9] = 12

  3. 物品3(重量5,价值6,最多选2次)拆分成 1, 1

    • dp[5] = 6, dp[10] = 12

最终 dp[10] = 12


总结:

  • 01 背包: 只能选 0 或 1 次,倒序遍历容量。

  • 完全背包: 可选无限次,正序遍历容量。

  • 多重背包: 每种物品最多选 Si 次,二进制拆分优化

http://www.dtcms.com/a/109792.html

相关文章:

  • 【PHP】- 项目通用目录架构及示例demo
  • 【LLM之评测】AlignBench: Benchmarking Chinese Alignment of Large Language Models
  • Docker 常用指令速查
  • TDengine 重磅功能虚拟表
  • Spring Security(maven项目) 3.1.0
  • 青少年编程与数学 02-015 大学数学知识点 06课题、离散数学
  • Linux驱动开发进阶(三)- 热插拔机制
  • Scala基础知识
  • 数据结构学习
  • 混杂模式(Promiscuous Mode)与 Trunk 端口的区别详解
  • UEFI镜像结构布局
  • 蓝桥杯刷题记录【并查集001】(2024)
  • DeepSeek真的超越了OpenAI吗?
  • 黑马点评项目总结
  • 迭代器、迭代对象的 __iter__() 和 __next__()详解
  • 使用Python快速接入DeepSeek API的步骤指南
  • 【Python使用】嘿马python数据分析教程第2篇:会员存量增量分析,增量等级分布分析【附代码文档】
  • 计算机网络-TCP的流量控制
  • 蓝桥杯嵌入式16届———LCD模块
  • 批量删除git本地分支和远程分支命令
  • 基于Docker容器部署DeepSeek-R1-Distill-Qwen-7B
  • CExercise04_2数组_1 利率在投资年份内每年的资产总价值
  • 虚拟电商-话费充值业务(五)充值成功逻辑和网络异常重试逻辑
  • Spring Boot 集成Redis 的Lua脚本详解
  • HCIP-12 中间系统到中间系统基础
  • 深度学习与神经网络 | 邱锡鹏 | 第三章学习笔记
  • 根据源码分析vue中nextTick的实现原理
  • makefile , CFALGS 与 EXTRA CFLAGS
  • 【HarmonyOS Next之旅】DevEco Studio使用指南(九)
  • 奇数和偶数的求法c++