1. 水库溃坝填补问题解析
最近在准备华为OD机试时遇到一道很有意思的题目——水库溃坝填补。这道题考察的是对实际问题的抽象建模能力,以及如何运用算法思维解决工程问题。下面我将详细解析这道题的解题思路,并提供多种语言的实现代码。
1.1 题目理解与建模
题目描述的是水库溃坝后的填补场景:
- 两侧坝岩高度相等且坚固
- 坝口用宽度为1的柱子高度图表示(非负整数数组)
- 填补材料是宽度为1、高度不一的木材(非负整数数组)
- 目标是用最优填补策略让溃口面积变为最小
举个例子:
- 坝口数组:[3,0,0]
- 两侧坝岩高度:7
- 原始溃口面积计算:(7-3)+(7-0)+(7-0)=18
- 木材数组:[4,7,4,3,3,5]
- 最优填补后面积可以减小
1.2 解题思路分析
这个问题可以抽象为一个典型的贪心算法问题。核心思路是:
- 计算每个坝口位置的当前高度与坝岩高度的差值(即需要填补的高度)
- 将这些差值按从大到小排序
- 将木材也按从大到小排序
- 用最大的木材填补最大的缺口,以此类推
这样做的原理是:最大的缺口对总面积影响最大,优先用最大的木材填补能最大化减少总面积。
1.3 算法实现步骤
具体实现步骤如下:
- 计算每个坝口位置的缺口高度(坝岩高度-当前高度)
- 对缺口高度数组和木材高度数组分别进行降序排序
- 使用双指针法:
- 一个指针遍历缺口数组
- 一个指针遍历木材数组
- 尽可能用最大的木材填补最大的缺口
- 计算填补后的剩余缺口总面积
1.4 代码实现(C++)
cpp复制#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int minDamArea(int damHeight, vector<int>& dam, vector<int>& woods) {
// 计算缺口高度
vector<int> gaps;
for (int h : dam) {
gaps.push_back(damHeight - h);
}
// 排序缺口和木材(降序)
sort(gaps.begin(), gaps.end(), greater<int>());
sort(woods.begin(), woods.end(), greater<int>());
int i = 0, j = 0;
int n = gaps.size(), m = woods.size();
// 使用双指针填补缺口
while (i < n && j < m) {
if (woods[j] >= gaps[i]) {
gaps[i] = 0; // 完全填补
i++;
j++;
} else {
gaps[i] -= woods[j]; // 部分填补
j++;
}
}
// 计算剩余缺口总面积
int total = 0;
for (int gap : gaps) {
total += gap;
}
return total;
}
int main() {
int damHeight = 7;
vector<int> dam = {3, 0, 0};
vector<int> woods = {4, 7, 4, 3, 3, 5};
cout << "最小剩余缺口面积: " << minDamArea(damHeight, dam, woods) << endl;
return 0;
}
