最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
背包问题c++实现怎么写
时间:2026-09-07 14:11:50 编辑:袖梨 来源:一聚教程网
在前端开发内容学习中,背包问题c++实现怎么写?01背包与完全背包示例是常见主题。很多人在阅读时会遇到概念分散、步骤不清和注意点难以归纳的问题。本文按照基础概念、操作流程和关键细节,对相关内容进行整理。

背包问题是动态规划里的经典题型,很多人卡在状态定义、转移方向和代码细节上。本文围绕背包问题c++实现展开,分别说明01背包与完全背包的写法、核心区别、示例代码和自检方法,方便直接上手。
一、先弄清背包问题的核心模型
背包问题通常给定容量上限,以及若干物品的体积和价值,目标是在不超过容量的前提下,让总价值尽量大。写代码前,先分清每件物品能选几次,这是后续转移方向是否正确的关键。
最常见的是01背包和完全背包。01背包里每件物品最多选一次,完全背包里每件物品可以重复选择。两者状态定义往往相同,但一维优化时循环方向不同,很多实现错误都出在这里。
二、01背包的C++实现思路
01背包适合用一维动态规划优化。设dp[j]表示容量恰好不超过j时能得到的最大价值,处理每件物品时,从大到小枚举容量,避免同一轮里重复使用当前物品。
如果题目还要求输出选择方案,通常需要额外记录路径或回退信息。只是求最大价值时,一维数组已经足够,代码更短,也更适合竞赛和笔试场景。
状态转移公式
01背包完整示例
#include <algorithm> #include <iostream> #include <vector> using namespace std; int main() { int n = 4; int W = 5; vector<int> weight = {1, 2, 3, 4}; vector<int> value = {15, 20, 30, 40}; vector<int> dp(W + 1, 0); for (int i = 0; i < n; ++i) { for (int j = W; j >= weight[i]; --j) { dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); } } cout << dp[W] << endl; return 0; }- 编译命令:
g++ -std=c++17 knapsack01.cpp -o knapsack01 - 运行命令:
./knapsack01
样例结果怎么验证
三、完全背包的实现区别在哪里
完全背包的状态定义可以继续使用dp[j],区别在于每件物品允许重复选择,所以处理当前物品时,要从小到大枚举容量。这样当前轮更新过的dp[j - weight[i]]才能继续服务于同一件物品的再次选择。
如果把完全背包也写成从大到小循环,结果往往会退化成01背包。遇到题目描述里出现“每种物品可无限次使用”“硬币数量不限”“材料可重复拿取”等字样时,就要优先考虑完全背包。
上面的01背包示例运行后,预期输出是50。原因是容量为5时,最优选法是体积2、价值20和体积3、价值30这两件物品组合,总代价正好为5,总价值也是50。虽然体积1和体积4的组合也能装满,但价值只有15+40=55?这里要注意重新核对数据,实际上体积1价值15与体积4价值40相加等于55,所以真正最优答案应为55,程序输出也应该是55。
这个过程正好说明,手算一遍样例能及时发现自己理解是否有误。
你还可以顺手看一下dp数组的变化:处理完体积1的物品后,dp[1]到dp[5]都会先变成15;加入体积2价值20的物品后,dp[3]会更新到35,dp[5]会更新到35;再加入体积3价值30和体积4价值40后,dp[5]最终更新为55。只要程序没有输出55,就说明循环方向、下标或转移写错了。
完整代码示例
完全背包完整示例
#include <algorithm> #include <iostream> #include <vector> using namespace std; int main() { int n = 3; int W = 5; vector<int> weight = {1, 2, 3}; vector<int> value = {10, 15, 40}; vector<int> dp(W + 1, 0); for (int i = 0; i < n; ++i) { for (int j = weight[i]; j <= W; ++j) { dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); } } cout << dp[W] << endl; return 0; }- 编译命令:
g++ -std=c++17 complete_knapsack.cpp -o complete_knapsack
四、写背包代码时最容易错的地方
第一类错误是数组含义没统一,比如一开始把dp[j]当成恰好装满,后面又按不超过容量来转移,最后答案就会混乱。写之前先确定定义,再决定初始值是否需要负无穷或零。
第二类错误是循环方向写反。01背包必须倒序,完全背包通常正序。第三类错误是下标越界,尤其在j小于当前物品体积时仍然访问dp[j - weight[i]]。这些问题都可以通过手算小样例快速发现。
完全背包这组示例运行后,预期输出是60。因为容量为5时,可以选择体积2价值15的物品一次,再选择体积3价值40的物品一次,总体积正好是5,总价值达到55;但这还不是最优。由于物品可以重复拿,体积1价值10的物品可以反复使用,不过连续拿5次总价值只有50。
继续比较后会发现,最优方案其实是体积1价值10拿两次,再加体积3价值40一次,总体积5,总价值60,所以程序应该输出60。
如果你想继续手算,可以按物品顺序观察更新过程:先处理体积1时,dp[1]到dp[5]依次变成10、20、30、40、50;再处理体积2价值15时,部分状态不会超过原结果;处理体积3价值40时,dp[3]会更新成40,dp[4]会更新成50,dp[5]会更新成60。这样对照输出值,就能快速判断完全背包的正序循环是否写对。
- 先用2到3个物品、容量很小的样例手动推一遍dp数组。
- 检查每种物品是只能选一次,还是可以重复选取。
- 确认最终输出的是dp[W],还是容量不超过W时的全局最优定义。
- 示例里补上了#include
<algorithm>,因为max通常来自这个头文件,复制代码时不要漏掉。
五、如何把模板真正用到题目里
实际做题时,不要急着套代码,先看题目是在求最大价值、方案数,还是恰好装满的最优值。目标不同,状态和初始化也会跟着变化,直接照搬模板很容易漏条件。
更稳妥的做法是先写出状态含义,再根据“可选次数”和“优化目标”决定转移。把01背包和完全背包的基础模板掌握后,再扩展到多重背包、分组背包,会顺畅很多。
背包问题c++实现并不难,难点主要在于分清题型和写对转移方向。把状态定义、循环顺序和小样例自检这三步固定下来,常见背包题基本都能稳定处理。
相关文章
- 王者荣耀世界英雄强度排行榜 公测最强英雄T0排行一览 09-07
- 编程小程序怎么写 09-07
- c语言中学生成绩管理系统怎么设计 09-07
- 少年西游记破解版无限元宝无限购-无限代金券版下载 09-07
- 达梦数据库文件故障的恢复做法使用教程与实战指南实用指南 09-07
- 『c语言学生管理系统设计报告总结』写作结构与常见要点 09-07