题解:学而思编程 热气球升空

【题目来源】

学而思编程:热气球升空

【题目描述】

小猴想用热气球运送一些物品,一共有 \(n\) 个物品,第 \(i\) 个的体积为 \(v_i\)​,重量为 \(w_i\)​。

小猴的热气球最多只能让重量为 \(m\) 的物体顺利升空,要运送的物品都要装到热气球的吊篮中。小猴想要在顺利升空的前提下,运送总体积最多的物品,但是更大的体积意味着更大的吊篮,吊篮体积必须大于等于要运送的物品总体积。

小猴可以使用任意大小的吊篮,一个体积为 \(V\) 的吊篮的重量是 \(V×c\)。只有物品重量加吊篮的重量总和不超过 \(m\) 时,气球才能顺利升空。

求出可以让小猴的气球升空的最大吊篮体积(这也是能运送的最大物品总体积)。

【输入】

\(1\) 行,\(3\) 个正整数 \(n,m,c\)

接下来 \(n\) 行,每行两个正整数 \(v_i,w_i\)

【输出】

\(1\) 行,输出最大吊篮体积。如果无法让任何物品升空,输出 \(0\)

【输入样例】

6 80 2
6 12
11 14
7 18
5 14
4 7
10 8

【输出样例】

25

【核心思想】

  1. 问题分析:给定 \(n\) 个物品,每个物品有体积 \(v_i\) 和重量 \(w_i\)。热气球总重量限制为 \(m\),吊篮体积为 \(V\) 时重量为 \(V \times c\)。需要选择若干物品装入吊篮,使得物品总体积等于吊篮体积 \(V\),且物品总重量加上吊篮重量不超过 \(m\)。求最大的可行吊篮体积 \(V\)。这是一个01背包(最值型)问题,关键在于将吊篮重量成本纳入物品成本,然后求满足重量限制的最大体积。

  2. 算法选择

    • 01背包(最值型)dp[j] 表示凑出总体积恰好为 \(j\) 时的最小总成本(物品重量 + 吊篮重量)
    • 成本计算:每个物品的实际成本 = 物品重量 \(w_i\) + 物品体积 \(v_i \times c\)(因为体积为 \(v_i\) 的物品需要吊篮提供 \(v_i\) 的体积,对应吊篮重量 \(v_i \times c\)
    • 逆序枚举:保证每个物品只选一次
  3. 关键步骤

    • 初始化dp[0] = 0(体积为0时成本为0),其余 dp[j] = INF
    • 01背包
      • 遍历每个物品 \(i\)
      • 逆序枚举体积 \(j\)\(MAXV\)\(v_i\)
      • 状态转移:dp[j] = min(dp[j], dp[j - v[i]] + w[i] + v[i] * c)
    • 查找答案:从大到小遍历体积 \(j\),找到第一个满足 dp[j] <= m\(j\),即为最大可行体积
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \times MAXV)\)\(MAXV = 5000\) 为最大体积上限
    • 空间复杂度:\(O(MAXV)\),一维DP数组
  5. 01背包与成本转换的核心思想

    • 问题转化:将吊篮重量成本分摊到每个物品上,物品 \(i\) 的总成本 = 自身重量 \(w_i\) + 所占吊篮体积成本 \(v_i \times c\)
    • 最值型01背包dp[j] 表示凑出体积 \(j\) 的最小成本,而非最大价值
    • 恰好装满:目标是找到体积恰好为 \(j\) 的方案,而非不超过 \(j\)
    • 答案查找:从大到小遍历,找到第一个成本不超过限制的最大体积
    • 适用于带附加成本的背包问题、资源分配类问题

【算法标签】

01背包

【代码详解】

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

// 定义长整型别名,便于处理大数据
#define int long long

// ================= 常量与全局变量 =================

const int N = 5005;      // 最大体积上限

int n;                   // 物品数量
int m;                   // 总预算上限
int c;                   // 单位体积的附加成本系数
int sumV;                // 未使用的变量(保留原样)
int ans;                 // 最终答案

int v[N];                // 每个物品的体积
int w[N];                // 每个物品的基础成本

int dp[N];               // 动态规划数组
                         // dp[j] 表示凑出总体积恰好为 j 时的最小总成本

// ================= 主函数 =================
signed main()
{
    // 读取物品数量、预算上限和附加成本系数
    cin >> n >> m >> c;

    // 读取每个物品的体积和基础成本
    for (int i = 1; i <= n; i++)
    {
        cin >> v[i] >> w[i];
    }

    // 初始化 dp 数组为无穷大
    memset(dp, 0x3f, sizeof(dp));
    dp[0] = 0;              // 体积为 0 时成本为 0

    // 01 背包:每个物品只能选一次
    for (int i = 1; i <= n; i++)
    {
        // 逆序枚举体积,保证每个物品只使用一次
        for (int j = 5000; j >= v[i]; j--)
        {
            // 总成本 = 基础成本 + 体积 × 附加成本系数
            dp[j] = min(dp[j], dp[j - v[i]] + w[i] + v[i] * c);
        }
    }

    // 从大到小找到第一个成本不超过预算的体积
    for (int j = 5000; j >= 0; j--)
    {
        if (dp[j] <= m)     // 如果凑出体积 j 的成本不超过预算
        {
            ans = j;        // 记录该体积
            break;          // 找到最大体积后退出
        }
    }

    // 输出最大可行体积
    cout << ans << endl;

    return 0;
}

【运行结果】

6 80 2
6 12
11 14
7 18
5 14
4 7
10 8
25
posted @ 2026-06-17 17:24  团爸讲算法  阅读(6)  评论(0)    收藏  举报