题解:洛谷 P2676 Bookshelf
【题目来源】
洛谷:P2676 [USACO07DEC] Bookshelf B - 洛谷(luogu.com.cn)
【题目描述】
Farmer John 最近为奶牛们的图书馆添置了一个巨大的书架,尽管它是如此的大,但它还是几乎瞬间就被各种各样的书塞满了。现在,只有书架的顶上还留有一点空间。
所有 \(N(1\le N\le 20,000)\) 头奶牛都有一个确定的身高 \(H_i(1\le H_i\le 10,000)\)。设所有奶牛身高的和为 \(S\)。书架的高度为 \(B\),并且保证 \(1\le B\le S\lt 2,000,000,007\)。
为了够到比最高的那头奶牛还要高的书架顶,奶牛们不得不像演杂技一般,一头站在另一头的背上,叠成一座“奶牛塔”。当然,这个塔的高度,就是塔中所有奶牛的身高之和。为了往书架顶上放东西,所有奶牛的身高和必须不小于书架的高度。
显然,塔中的奶牛数目越多,整座塔就越不稳定,于是奶牛们希望在能够到书架顶的前提下,让塔中奶牛的数目尽量少。现在,奶牛们找到了你,希望你帮她们计算这个最小的数目。
【输入】
- 第 \(1\) 行: \(2\) 个用空格隔开的整数:\(N\) 和 \(B\);
- 第 \(2\dots N+1\) 行:第 \(i+1\) 行是 \(1\) 个整数:\(H_i\)。
【输出】
第 \(1\) 行:输出 \(1\) 个整数,即最少要多少头奶牛叠成塔,才能够到书架顶部
【输入样例】
6 40
6
18
11
13
19
11
【输出样例】
3
【核心思想】
-
问题分析:给定 \(N\) 头奶牛的身高 \(H_i\) 和书架高度 \(B\),要求选出最少数量的奶牛,使其身高之和 \(\ge B\)。这是一个贪心问题,关键在于每次选择当前最高的奶牛,以最快速度达到目标高度。
-
算法选择:
- 贪心策略(Greedy):每次选择剩余奶牛中身高最高的,直到累计身高 \(\ge B\)
- 降序排序:将奶牛按身高从大到小排序,依次选取前 \(k\) 头
-
关键步骤:
- 初始化:读取 \(N\)(奶牛数量)、\(B\)(书架高度),以及 \(H[1..N]\)(每头奶牛的身高)
- 降序排序:将数组 \(H\) 按从大到小排序,排序后 \(H_1 \ge H_2 \ge \dots \ge H_N\)
- 贪心选取:
- 初始化累计高度 \(\text{tmp} = 0\),答案计数 \(\text{ans} = 0\)
- 遍历 \(i\) 从 \(1\) 到 \(N\):
- \(\text{tmp} += H_i\):将当前最高奶牛的身高加入累计高度
- \(\text{ans}++\):奶牛数量加 \(1\)
- 若 \(\text{tmp} \ge B\),则立即跳出循环,输出 \(\text{ans}\)
- 输出答案 \(\text{ans}\)
-
时间/空间复杂度:
- 时间复杂度:\(O(N \log N)\),主要来自排序操作,贪心遍历为 \(O(N)\)
- 空间复杂度:\(O(N)\),存储 \(N\) 头奶牛的身高
-
贪心算法的核心思想:
- 局部最优即全局最优:每次选最高的奶牛,确保用最少的数量最快达到目标高度
- 排序预处理:通过降序排序将"选最高"转化为"依次取前 \(k\) 个"
- 正确性证明:假设最优解选了 \(k\) 头奶牛,若存在某头未选奶牛比已选某头更高,交换后不会增加数量,因此选最高的 \(k\) 头一定最优
- 适用场景:目标是最小化选取数量,且每个元素的贡献可叠加(如求和)
- 适用于"用最少数量的元素使总和达到阈值"类问题
【解题思路】

【算法标签】
普及- #贪心
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, b, ans=0, tmp=0, a[20005];
bool cmp(int l, int r) { // 定义cmp函数
return l>r; // 返回更大的值
}
int main()
{
cin >> n >> b; // 输入a和b
for (int i=1; i<=n; i++) cin >> a[i]; // 输入n头奶牛的高度
sort(a+1, a+n+1, cmp); // 按照从大到小进行排序
while (tmp<b) { // 当奶牛的身高之和小于书架高度时
ans++; // 再增加一头奶牛
tmp+=a[ans]; // 并得到奶牛的身高之和
}
cout << ans; // 输出奶牛的头数
return 0;
}
【运行结果】
6 40
6
18
11
13
19
11
3
浙公网安备 33010602011771号