【c++】简单背包问题

描述

有一个背包能装的重量maxw(正整数,0≤maxw≤20000),同时有n件物品(0≤n≤100),每件物品有一个重量wi(正整数)和一个价值pi(正整数)。要求从这n件物品中任取若干件装入背包内,使背包的物品价值最大。

输入描述

第1行:背包最大载重maxw,物品总数n
第2行到第n+1行:每个物品的重量和价值

输出描述

一个数字即背包内物品最大价值

用例输入 1 

10 3
4 5
3 4
6 9

用例输出 1 

14

来源

动态规划 背包问题

一、问题分析:0-1 背包问题

这是经典的0-1 背包问题,核心约束是:

  1. 每件物品只能选择 “装” 或 “不装”(不能拆分);
  2. 装入物品的总重量不能超过背包最大载重maxw
  3. 目标是最大化装入物品的总价值。

由于maxw最大为 20000,n最大为 100,适合使用动态规划(DP) 中的 “滚动数组” 优化方案,既能保证时间复杂度,又能节省空间。

二、动态规划解法思路

1. 定义 DP 数组

dp[j]表示:背包载重为j时,能装入的最大价值
数组长度为maxw + 1(覆盖从 0 到maxw的所有载重情况)。

2. 初始化 DP 数组
  • 初始时,dp[0...maxw]均为 0:因为载重为 0 时无法装任何物品,价值为 0;其他载重初始状态也为 0(尚未选择物品)。
3. 状态转移方程

对于每件物品(重量w,价值p),从后向前遍历载重j(从maxww):
dp[j] = max(dp[j], dp[j - w] + p)

  • 解释:
    • dp[j](更新前):不装当前物品时,载重j的最大价值;
    • dp[j - w] + p:装当前物品时,载重j的价值(即 “载重j - w的最大价值” 加上当前物品价值);
    • 取两者最大值,更新dp[j]为最优解。
4. 为什么从后向前遍历?

避免同一件物品被重复装入。如果从前向后遍历,dp[j - w]可能已包含当前物品的价值,导致多次选择同一物品(变成 “完全背包” 问题)。

三、C++ 代码实现

cpp

运行

#include <iostream>
#include <vector>
#include <algorithm>  // 用于max函数

using namespace std;

int main() {
    // 1. 读取输入
    int maxw, n;
    cin >> maxw >> n;
    
    vector<int> weights(n);  // 存储物品重量
    vector<int> values(n);   // 存储物品价值
    
    for (int i = 0; i < n; ++i) {
        cin >> weights[i] >> values[i];
    }
    
    // 2. 初始化DP数组:dp[j]表示载重j时的最大价值
    vector<int> dp(maxw + 1, 0);
    
    // 3. 遍历每件物品,更新DP数组
    for (int i = 0; i < n; ++i) {
        int w = weights[i];  // 当前物品重量
        int p = values[i];  // 当前物品价值
        // 从后向前遍历载重,避免重复装同一物品
        for (int j = maxw; j >= w; --j) {
            dp[j] = max(dp[j], dp[j - w] + p);
        }
    }
    
    // 4. 输出结果:背包最大载重maxw对应的最大价值
    cout << dp[maxw] << endl;
    
    return 0;
}

四、代码运行示例(以用例输入 1 为例)

输入:

plaintext

10 3
4 5
3 4
6 9
执行过程:
  1. 初始化dp[0...10] = [0,0,0,0,0,0,0,0,0,0,0]
  2. 处理第 1 件物品(w=4, p=5):
    • 遍历 j=10→4,更新dp[4]=5dp[5]=5、...、dp[10]=5
  3. 处理第 2 件物品(w=3, p=4):
    • 遍历 j=10→3,例如dp[7] = max(5, dp[4]+4=9)→9,dp[10] = max(5, dp[7]+4=13)→13;
  4. 处理第 3 件物品(w=6, p=9):
    • 遍历 j=10→6,dp[10] = max(13, dp[4]+9=14)→14;
  5. 最终dp[10] = 14,输出结果。

五、复杂度分析

  • 时间复杂度:O (n × maxw)。n 为物品数(100),maxw 为最大载重(20000),总运算量约 2×10⁶,效率极高。
  • 空间复杂度:O (maxw)。使用滚动数组优化后,空间从二维(n×maxw)降至一维(maxw+1),节省内存。

六、边界情况处理

  1. maxw=0时:背包无法装任何物品,输出 0;
  2. n=0时:无物品可装,输出 0;
  3. 当物品重量超过maxw时:该物品无法装入,自动跳过。

以上代码已涵盖所有边界情况,无需额外特殊处理。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值