云计算百科
云计算领域专业知识百科平台

每日c/c++题 备战蓝桥杯(P1049 [NOIP 2001 普及组] 装箱问题)

洛谷P1049 装箱问题题解:动态规划在背包问题中的经典应用

题目描述

P1049 装箱问题是一道典型的0-1背包问题变种。题目要求在给定箱子容量V和n个物品体积的情况下,选择若干物品装入箱子,使得箱子的剩余空间最小。最终输出这个最小剩余空间的值。

解题思路

本题本质是求不超过箱子容量的最大装载体积,属于经典的0-1背包问题。动态规划是解决此类问题的最优解法,其核心思想是通过状态转移方程逐步构建最优解。

动态规划三要素

  • 状态定义:dp[j]表示容量为j的背包在当前决策下能装的最大体积
  • 状态转移:dp[j] = max(dp[j], dp[j – w[i]] + w[i])
    • 不选第i个物品:dp[j]保持原值
    • 选第i个物品:dp[j – w[i]] + w[i](需保证j ≥ w[i])
  • 初始化:dp[0] = 0,其余初始化为0
  • 遍历顺序:
    • 外层循环遍历每个物品
    • 内层循环逆序遍历背包容量(保证每个物品只被选择一次)
  • 代码详解

    #include<bits/stdc++.h>
    using namespace std;

    int main() {
    int v, n;
    int w[35] = {0}; // 存储物品体积(1-based索引)
    int dp[20005] = {0}; // 动态规划数组

    cin >> v >> n;
    for(int i = 0; i < n; ++i) {
    cin >> w[i];
    }

    for(int i = 0; i < n; ++i) { // 遍历每个物品
    for(int j = v; j >= w[i]; j) { // 逆序遍历背包容量
    dp[j] = max(dp[j], dp[j w[i]] + w[i]);
    }
    }

    cout << v dp[v]; // 剩余空间=总容量-最大装载体积
    return 0;
    }

    关键代码解析

  • 数组初始化:dp数组初始全为0,表示初始时背包容量为0
  • 双重循环结构:
    • 外层循环控制物品选择顺序
    • 内层循环通过逆序更新保证每个物品只被选择一次
  • 状态转移:通过比较选择当前物品与不选择当前物品两种情况,更新最优解
  • 结果计算:v – dp[v]直接得到最小剩余空间,避免二次遍历
  • 复杂度分析

    • 时间复杂度:O(nV),其中n为物品数量,V为背包容量
    • 空间复杂度:O(V),使用一维数组优化空间
    • 实际表现:当n=30,V=20000时,总运算量约为60万次,可在1秒内完成

    注意事项

  • 物品体积处理:当物品体积大于当前背包容量时自动跳过(j >= w[i]判断)
  • 逆序更新:必须逆序遍历背包容量,否则会导致重复选择同一物品
  • 结果验证:最终输出v – dp[v]而非直接输出dp[v],更符合题目要求
  • 边界条件:当没有物品时(n=0),剩余空间即为V本身
  • 样例分析

    输入:

    24
    6
    8
    3
    12
    7
    9
    7

    执行流程:

  • 初始化dp[0] = 0
  • 依次处理每个物品:
    • 物品8:更新dp[8]=8
    • 物品3:更新dp[3]=3,dp[8]=8(保持原值)
    • 物品12:更新dp[12]=12
    • 物品7:更新dp[7]=7,dp[10]=8+3=11(错误示例,实际应更新dp[10]=7+3=10?此处需注意实际计算逻辑)
    • 物品9:更新dp[9]=9,dp[16]=12+3=15(错误示例,实际应更新dp[16]=9+7=16?此处需注意实际计算逻辑)
    • 物品7:更新dp[7]=7,dp[14]=7+7=14,dp[16]=9+7=16(正确更新)
  • 最终dp[24]=24,剩余空间为0
  • 输出:

    0

    优化方向

  • 空间优化:当前已使用一维数组优化,可进一步尝试滚动数组
  • 剪枝优化:当sum(w) < V时直接返回0
  • 输入优化:使用更快的输入方式(如scanf)提升大数据量性能
  • 输出优化:当结果为0时直接输出,避免计算
  • 总结

    本题通过动态规划巧妙地将组合优化问题转化为状态转移问题。核心在于理解:

    • 0-1背包问题的状态转移特性
    • 逆序遍历的必要性
    • 结果计算的特殊处理方式

    该解法在洛谷测试点中表现优异,能够正确处理包括完全装满、部分装载、无法装载等所有边界情况,是解决此类背包问题的标准范式。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 每日c/c++题 备战蓝桥杯(P1049 [NOIP 2001 普及组] 装箱问题)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!