时间限制:C/C++ 1000MS,其他语言 2000MS
内存限制:C/C++ 128MB,其他语言 256MB
难度:困难
描述
公元 2919 年,人类终于发现了一颗宜居星球——X 星。现想在 X 星一片连绵起伏的山脉间建一个天热蓄水库,如何选取水库边界,使蓄水量最大?
山脉用正整数数组 s 表示,每个元素代表山脉的高度。选取山脉上两个点作为蓄水库的边界,则边界内的区域可以蓄水,蓄水量需排除山脉占用的空间。
蓄水量的高度为两边界的最小值。 如果出现多个满足条件的边界,应选取距离最近的一组边界。 输出边界下标(从 0 开始)和最大蓄水量;如果无法蓄水,则返回 0,此时不返回边界。
例如,当山脉为 s=[3,1,2]时,则选取 s[0]和 s[2]作为水库边界,最大蓄水量为 1,此时输出:0 2:1
当山脉 s = [3,2,1]时,不存在合理的边界,此时输出 0。
输入描述
一行正整数,用空格隔开,例如输入1 2 3表示 s = [1,2,3]
输出描述
当存在合理的水库边界时,输出左边界、空格、右边界、英文冒号、蓄水量,例如0 2:1
当不存在合理的水库边界时,输出 0。
用例输入 1 **
1 9 6 2 5 4 9 3 7
用例输出 1 **
1 6:19
提示
经过分析,选取 s[1]和 s[6] 时,水库蓄水量为 3+7+4+5 = 19 为最大蓄水量
双指针
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 主函数
int main() {
// 输入山脉高度数组
vector<int> s;
int num;
while (cin >> num) {
s.push_back(num);
if (cin.get() == '\n') break; // 按行读取输入
}
int n = s.size();
if (n < 3) { // 至少需要三个点才能形成蓄水区域
cout << "0" << endl;
return 0;
}
int left = 0, right = n - 1;
int max_water = 0;
pair<int, int> result = {0, 0}; // 存储最优边界
while (left < right) {
// 当前边界的蓄水高度
int height = min(s[left], s[right]);
// 计算当前区域的蓄水量
int water = height * (right - left - 1);
for (int i = left + 1; i < right; ++i) {
water -= s[i]; // 减去山脉占用的空间
}
// 更新最大蓄水量和边界
if (water > max_water) {
max_water = water;
result = {left, right};
}
// 移动指针
if (s[left] < s[right]) {
left++;
} else {
right--;
}
}
// 如果最大蓄水量为 0,则无法蓄水
if (max_water == 0) {
cout << "0" << endl;
} else {
// 输出结果
cout << result.first << " " << result.second << ":" << max_water << endl;
}
return 0;
}
package main
import (
"fmt"
)
func maxWaterStorage(s []int) string {
n := len(s)
if n < 3 { // 至少需要三个点才能形成蓄水区域
return "0"
}
left, right := 0, n-1
maxWater := 0
result := [2]int{0, 0} // 存储最优边界
for left < right {
// 当前边界的蓄水高度
height := min(s[left], s[right])
// 计算当前区域的蓄水量
water := height*(right-left-1) - sum(s[left+1:right])
// 更新最大蓄水量和边界
if water > maxWater {
maxWater = water
result = [2]int{left, right}
}
// 移动指针
if s[left] < s[right] {
left++
} else {
right--
}
}
// 如果最大蓄水量为 0,则无法蓄水
if maxWater == 0 {
return "0"
}
// 输出结果
return fmt.Sprintf("%d %d:%d", result[0], result[1], maxWater)
}
// 辅助函数:计算数组的和
func sum(arr []int) int {
total := 0
for _, num := range arr {
total += num
}
return total
}
// 辅助函数:求最小值
func min(a, b int) int {
if a < b {
return a
}
return b
}
// 主函数
func main() {
var input []int
var num int
// 输入山脉高度数组
for {
_, err := fmt.Scan(&num)
if err != nil {
break
}
input = append(input, num)
}
// 调用函数并输出结果
fmt.Println(maxWaterStorage(input))
}
def max_water_storage(s):
n = len(s)
if n < 3: # 至少需要三个点才能形成蓄水区域
return "0"
left, right = 0, n - 1
max_water = 0
result = (0, 0) # 存储最优边界
while left < right:
# 当前边界的蓄水高度
height = min(s[left], s[right])
# 计算当前区域的蓄水量
water = height * (right - left - 1) - sum(s[left + 1:right])
# 更新最大蓄水量和边界
if water > max_water:
max_water = water
result = (left, right)
# 移动指针
if s[left] < s[right]:
left += 1
else:
right -= 1
# 如果最大蓄水量为 0,则无法蓄水
if max_water == 0:
return "0"
# 输出结果
return f"{result[0]} {result[1]}:{max_water}"
# 输入处理
if __name__ == "__main__":
import sys
input_data = list(map(int, sys.stdin.read().strip().split()))
print(max_water_storage(input_data))
单调栈
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
int main() {
vector<int> height;
int h;
while (cin >> h) {
height.push_back(h);
}
int n = height.size();
stack<int> st;
int x = -1, y = -1;
int ans = 0, area = 0;
for (int i = 0; i < n; i++) {
int h = height[i];
while (!st.empty() && h >= height[st.top()]) {
int top = height[st.top()];
st.pop();
if (!st.empty()) {
int d = min(height[st.top()], h) - top;
int w = i - st.top() - 1;
area += d * w;
if (area > ans) {
ans = area;
x = st.top();
y = i;
}
if (area == ans && (y - x > i - st.top())) {
x = st.top();
y = i;
}
}
}
if (st.empty()) {
area = 0;
}
st.push(i);
}
if (ans == 0) {
cout << 0 << endl;
} else {
cout << x << " " << y << ":" << ans << endl;
}
return 0;
}