元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
算法基础
▶
复杂度分析
时间复杂度
空间复杂度
渐进符号
▶
算法思想
分治法
贪心算法
回溯法
概率算法
枚举算法
递推算法
递归算法
动态规划
分支限界法
模拟算法
▶
算法分析
正确性证明
性能优化
算法比较
▶
搜索算法
▶
基本搜索
顺序搜索
二分搜索
插值搜索
▶
图搜索
深度优先搜索
广度优先搜索
启发式搜索
▶
高级搜索
双向搜索
A*算法
模式匹配
▶
排序算法
▶
比较类排序
冒泡排序
快速排序
归并排序
插入排序
选择排序
▶
非比较类排序
计数排序
基数排序
桶排序
▶
高级排序
堆排序
希尔排序
外部排序
拓扑排序
▶
图论算法
▶
图的表示
邻接矩阵
邻接表
边集数组
▶
最短路径
Dijkstra算法
Floyd算法
Bellman-Ford算法
最短路径概述
▶
生成树
Prim算法
Kruskal算法
并查集
最小生成树
▶
图的连通性
强连通分量
割点与桥
双连通分量
欧拉路径
▶
动态规划
▶
基础概念
最优子结构
重叠子问题
状态转移方程
▶
经典问题
背包问题
最长公共子序列
编辑距离
▶
优化技巧
空间优化
状态压缩
区间动态规划
▶
字符串算法
▶
字符串匹配
KMP算法
Boyer-Moore算法
Sunday算法
▶
字符串处理
字典树
后缀数组
字符串哈希
▶
压缩算法
游程编码
Huffman编码
LZ77算法
发布时间:
2025-03-21 19:49
↑
☰
# 背包问题 背包问题是动态规划中最经典的问题之一,它描述了在给定容量限制下,如何选择物品以获得最大价值的问题。本文将介绍几种常见的背包问题及其解法。 ## 0-1背包问题 ### 问题描述 给定n个物品,每个物品有重量w[i]和价值v[i],背包容量为W,每个物品只能选择0个或1个,求解能获得的最大价值。 ### 动态规划解法 ```go // 0-1背包问题的动态规划实现 func knapsack01(w []int, v []int, W int) int { n := len(w) // dp[i][j]表示前i个物品,容量为j时的最大价值 dp := make([][]int, n+1) for i := range dp { dp[i] = make([]int, W+1) } // 填充dp表格 for i := 1; i <= n; i++ { for j := 0; j <= W; j++ { if j >= w[i-1] { // 可以选择第i个物品 dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]]+v[i-1]) } else { // 不能选择第i个物品 dp[i][j] = dp[i-1][j] } } } return dp[n][W] } // 空间优化版本 func knapsack01Optimized(w []int, v []int, W int) int { n := len(w) dp := make([]int, W+1) for i := 0; i < n; i++ { for j := W; j >= w[i]; j-- { dp[j] = max(dp[j], dp[j-w[i]]+v[i]) } } return dp[W] } func max(a, b int) int { if a > b { return a } return b } ``` ## 完全背包问题 ### 问题描述 与0-1背包问题类似,但每个物品可以选择无限次。 ### 动态规划解法 ```go // 完全背包问题的实现 func unboundedKnapsack(w []int, v []int, W int) int { n := len(w) dp := make([]int, W+1) for i := 0; i < n; i++ { for j := w[i]; j <= W; j++ { dp[j] = max(dp[j], dp[j-w[i]]+v[i]) } } return dp[W] } ``` ## 多重背包问题 ### 问题描述 每个物品有特定的可用数量限制。 ### 动态规划解法 ```go // 多重背包问题的实现 func multipleKnapsack(w []int, v []int, nums []int, W int) int { n := len(w) dp := make([]int, W+1) for i := 0; i < n; i++ { // 将多重背包转化为0-1背包 for k := 1; k <= nums[i]; k *= 2 { nums[i] -= k for j := W; j >= k*w[i]; j-- { dp[j] = max(dp[j], dp[j-k*w[i]]+k*v[i]) } } if nums[i] > 0 { for j := W; j >= nums[i]*w[i]; j-- { dp[j] = max(dp[j], dp[j-nums[i]*w[i]]+nums[i]*v[i]) } } } return dp[W] } ``` ## 分组背包问题 ### 问题描述 物品被分为多个组,每组最多选择一个物品。 ### 动态规划解法 ```go // 分组背包问题的实现 func groupKnapsack(groups [][][]int, W int) int { dp := make([]int, W+1) for _, group := range groups { for j := W; j >= 0; j-- { for _, item := range group { w, v := item[0], item[1] if j >= w { dp[j] = max(dp[j], dp[j-w]+v) } } } } return dp[W] } ``` ## 优化技巧 ### 空间优化 1. 一维数组优化 - 使用滚动数组 - 逆序更新避免重复计算 2. 状态压缩 - 位运算优化 - 记录选择方案 ### 剪枝优化 1. 可行性剪枝 - 重量超过限制直接跳过 - 价值上界剪枝 2. 最优性剪枝 - 排序后剪枝 - 价值密度优化 ## 实际应用 ### 应用场景 1. 资源分配 - 服务器资源分配 - 投资组合优化 - 任务调度 2. 切割问题 - 材料切割优化 - 时间分配 - 空间规划 ### 扩展问题 1. 带依赖的背包 - 物品之间有依赖关系 - 需要考虑选择顺序 2. 泛化背包问题 - 多维费用背包 - 树形依赖背包 - 背包问题变种 ## 性能分析 ### 时间复杂度 1. 0-1背包 - 基本版本:O(nW) - 空间优化版本:O(nW) 2. 完全背包 - 基本版本:O(nW) - 优化版本:O(nW) 3. 多重背包 - 基本版本:O(nW∑k) - 二进制优化:O(nWlogS) ### 空间复杂度 1. 二维DP表格 - O(nW) 2. 一维优化 - O(W) ## 实践建议 ### 解题步骤 1. 问题分析 - 确定背包类型 - 分析约束条件 - 设计状态表示 2. 方程设计 - 写出状态转移 - 处理边界情况 - 考虑优化方向 3. 代码实现 - 选择合适数据结构 - 注意边界处理 - 考虑代码效率 ### 调试技巧 1. 使用小规模测试 - 验证基本功能 - 检查边界情况 - 找出特殊输入 2. 结果验证 - 检查最优性 - 验证可行性 - 输出选择方案 ## 总结 1. 问题特点 - 最优子结构 - 重叠子问题 - 多种变体 2. 解决方法 - 动态规划 - 状态设计 - 空间优化 3. 应用建议 - 理解问题本质 - 选择合适算法 - 注重实现效率