1.题目
问题描述
小U正在准备穿越一片广阔的沙漠。沙漠里有多个绿洲,每个绿洲设有补给站。所有补给站的收费相同,但提供的水量不同。从起点到终点共有 (D) 公里,小U需要规划在哪些补给站停留,以保证整个旅途中水的供应。
起点到终点的距离为 (D) 公里,小U初始携带 (W) 升水,每行走 1 公里消耗 1 升水。小U希望通过最少的补给次数安全到达终点。每个补给站的位置由 position[i]
表示,距离起点的公里数,supply[i]
表示该站可以提供的水量,单位为升。
请你帮助小U计算,要安全到达终点至少需要补给几次,或者判断是否根本无法到达终点,此时输出-1。
测试样例
样例1:
输入:d = 10, w = 4, position = [1, 4, 7], supply = [6, 3, 5]
输出:
1
样例2:
输入:d = 15, w = 3, position = [3, 6, 12], supply = [4, 5, 2]
输出:
-1
样例3:
输入:d = 20, w = 10, position = [5, 15], supply = [8, 6]
输出:
2
样例4:
输入:d = 7, w = 7, position = [], supply = []
输出:
0
样例5:
输入:d = 25, w = 8, position = [7, 13, 18], supply = [7, 6, 5]
输出:
3
2.思路
计算至少需要补给几次,使用贪心算法,优先选择补给多的点。
思路一:
如果当前水量走不到终点→当前是补给最多的点或当前水量不够走到下一个补给站→补给
思路二:√
建立一个最大堆,每经过一个补给站,就把这个补给站加入最大堆,一直到水不够的时候,就从堆中取最大的补给站补给
- 思路一是直接的贪心策略,虽然简单,但可能会在一些情况下不是最优解。例如,当你遇到一个补给站的水量相对较少,但它恰好是最优的补给站时,贪心的选择可能会导致最终的解决方案不是最优的。
- 思路二使用了最大堆,可以保证每次补给都是从水量最多的站点中取出,因此能更好地利用水资源,可能会得到更好的解答。而且,最大堆保证了每次选择的补给站是当前最优的,避免了贪心的局限性。
3.代码
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int solution(int d, int w, std::vector<int> position, std::vector<int> supply) {
// Please write your code here
int n = position.size();
// 将起点添加到补给站的列表中
position.push_back(0);
supply.push_back(w);
// 补给站信息加入stations
vector<pair<int, int>> stations;
for (int i = 0; i < n; i++) {
stations.push_back({position[i], supply[i]});
}
stations.push_back({d, 0}); // 终点
sort(stations.begin(), stations.end()); // 按照位置升序排列
priority_queue<int> maxHeap; // 用于存储经过的补给站的水量(最大堆)
int currentWater = w;
int count = 0;
int prePosition = 0;
for (const auto& station : stations) {
int distance = station.first - prePosition;
currentWater -= distance;
// 当水不足以到达下一个站点时,从堆中补给
while (currentWater < 0 && !maxHeap.empty()) {
currentWater += maxHeap.top();
maxHeap.pop();
count++;
}
// 如果仍然水不足,说明无法到达终点
if (currentWater < 0) {
return -1;
}
// 将当前补给站的水量加入堆
maxHeap.push(station.second);
prePosition = station.first;
}
return count;
}
int main() {
// You can add more test cases here
std::vector<int> testPosition = {170, 192, 196, 234, 261, 269, 291, 404, 1055, 1121, 1150, 1234, 1268, 1402, 1725, 1726, 1727, 1762, 1901, 1970};
std::vector<int> testSupply = {443, 185, 363, 392, 409, 358, 297, 70, 189, 106, 380, 130, 126, 411, 63, 186, 36, 347, 339, 50};
std::cout << (solution(10, 4, std::vector<int>{1, 4, 7}, std::vector<int>{6, 3, 5}) == 1) << std::endl;
std::cout << (solution(2000, 200, testPosition, testSupply) == 5) << std::endl;
return 0;
}
注意:
std::sort
默认会对pair
进行排序时,首先按照 第一个元素 排序。如果第一个元素相同,才会按照 第二个元素 排序。priority_queue
默认是一个 最大堆(最大优先队列),即队头的元素总是当前队列中的最大元素。