华为 OD 机试:文件最小光盘备份策略
问题背景
在华为 OD 机试中,这类题目常考察对资源分配和贪心算法的理解。场景很直观:有若干文件需要刻录到容量固定的光盘上,每张盘 500MB,文件不可分割,求最少需要多少张盘。
核心难点
乍一看,把文件大小加起来除以 500 向上取整似乎可行,但忽略了'碎片'问题。比如两个 300MB 的文件,总大小 600MB,简单除法算出来是 2 张盘,但实际因为单盘上限 500MB,必须用两张盘分别装一个,结果也是 2 张。但如果是一个 400MB 和一个 200MB,总和 600MB,除法得 2 张,实际一张放不下,也得 2 张。关键在于如何组合能塞进同一张盘。
这其实是一个经典的装箱问题(Bin Packing Problem)变种。由于文件数量限制在 100 个以内,且文件大小为整数,我们可以采用排序后贪心的策略来逼近最优解。
解题思路
为了减少空余空间,最好的办法是让大文件优先占位。如果先把小文件塞进去,可能会留下一些无法容纳大文件的空隙。所以策略上,先将文件按大小从大到小排序。接着遍历每个文件,尝试放入当前已有的一张光盘中。如果当前所有光盘都放不下,就开启一张新光盘。最后记录使用的光盘总数。这种'首次适应递减'(First Fit Decreasing)算法在大多数面试场景下足够高效且逻辑清晰。
C++ 代码实现
下面给出完整的 C++ 实现,重点在于如何管理光盘的剩余空间。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
// 输入文件数量,虽然题目描述没明确说第一行是数量,但通常机试会有
// 这里假设输入是一组数据,具体根据实际 OJ 调整读取方式
// 假设先读入文件个数,再读入每个文件大小
if (!(cin >> n)) return 0;
vector<int> files(n);
for (int i = 0; i < n; ++i) {
cin >> files[i];
}
// 排序:从大到小
sort(files.begin(), files.end(), greater<int>());
vector<> discs;
disc_capacity = ;
( size : files) {
placed = ;
(& used : discs) {
(used + size <= disc_capacity) {
used += size;
placed = ;
;
}
}
(!placed) {
discs.(size);
}
}
cout << discs.() << endl;
;
}

