题解:洛谷 P2925 Hay For Sale
【题目来源】
洛谷:P2925 [USACO08DEC] Hay For Sale S - 洛谷
【题目描述】
农民 John 面临一个很可怕的事,因为防范力度不大所以他存储的所有稻草都被蟑螂吃光了,他将面临没有稻草喂养奶牛的局面。在奶牛断粮之前,John 拉着他的马车到农民 Don 的农场中买一些稻草给奶牛过冬。已知 John 的马车可以装的下 \(C(1\le C\le5\times10^4)\) 立方的稻草。
农民 Don 有 \(H(1\le H\le5\times10^3)\) 捆体积不同的稻草可供购买,每一捆稻草有它自己的体积 \(V_i(1\le V_i\le C)\)。面对这些稻草 John 认真的计算如何充分利用马车的空间购买尽量多的稻草给他的奶牛过冬。
现在给定马车的最大容积 \(C\) 和每一捆稻草的体积 \(V_i\),John 如何在不超过马车最大容积的情况下买到最大体积的稻草?他不可以把一捆稻草分开来买。
【输入】
第一行两个整数,分别为 \(C\) 和 \(H\)。
第 \(2\) 到 \(H+1\) 行:每一行一个整数代表第 \(i\) 捆稻草的体积 \(V_i\)。
【输出】
一个整数,为 John 能买到的稻草的体积。
【输入样例】
7 3
2
6
5
【输出样例】
7
【核心思想】
-
问题分析:给定马车容量 \(C\) 和 \(H\) 捆稻草,每捆体积 \(V_i\)(不可拆分),求在不超过容量 \(C\) 的前提下能装入的最大总体积。这是一个经典的01背包问题,每捆稻草是"物品",体积既是重量也是价值,背包容量为 \(C\)。
-
算法选择:
- 01背包(一维滚动数组):\(dp[j]\) 表示容量为 \(j\) 时的最大可装体积,逆序遍历容量保证每捆稻草只选一次
-
关键步骤:
- 读取输入:\(C\)(容量)和 \(H\)(物品数),以及 \(H\) 捆稻草的体积 \(V_i\)
- 初始化:\(dp[0..C] = 0\)
- 01背包递推(\(i\) 从 \(1\) 到 \(H\)):
- 对于 \(j\) 从 \(C\) 到 \(V_i\) 逆序:
- \(dp[j] = \max(dp[j],\ dp[j - V_i] + V_i)\)
- 对于 \(j\) 从 \(C\) 到 \(V_i\) 逆序:
- 输出 \(dp[C]\)
-
时间/空间复杂度:
- 时间复杂度:\(O(H \cdot C)\),\(H \le 5000\),\(C \le 50000\)
- 空间复杂度:\(O(C)\),一维滚动数组
-
01背包的核心思想:
- 选或不选:每捆稻草只有两种状态——选(占用 \(V_i\) 容量,获得 \(V_i\) 体积)或不选(不占用容量,体积不变)
- 逆序遍历保证唯一性:容量从大到小遍历,确保 \(dp[j - V_i]\) 是未选第 \(i\) 捆稻草时的状态,避免同一捆被重复选取
- 价值=体积:本题中每捆稻草的价值等于其体积,是01背包的特例,但递推公式不变
- 适用于"有限物品 + 容量约束 + 最大化装入量"类经典背包问题
【解题思路】

【算法标签】
普及- #01背包
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int C, h, v[5005], c[5005], dp[50005];
int main()
{
cin >> C >> h; // 输出背包最大体积和数量h
for (int i=1; i<=h; i++) { // 输入h捆干草的重量,其价值与重量相同
int tmp;
cin >> tmp;
c[i] = tmp;
v[i] = tmp;
}
for (int i=1; i<=h; i++) { // 01背包模板
for (int j=C; j>=v[i]; j--) {
dp[j] = max(dp[j], dp[j-v[i]]+c[i]);
}
}
cout << dp[C] << endl; // 输出结果
return 0;
}
【运行结果】
7 3
2
6
5
7
浙公网安备 33010602011771号