Description Link to heading
871.minimum-number-of-refueling-stops
Solution Link to heading
Dynamic programming Link to heading
In this problem, the number is finite, and there is a recurrence relation, so we can use dynamic programming to solve this problem.
Let dp[i][j]
means the furthest distance we can reach after passing throught i
stations and adding fuel for j
times. Obviously, i >= j
.
So we can discuss dp[i][j
] in two cases:
- We don’t add fuel at the
i
th station:dp[i][j] = dp[i - 1][j]
- We add fuel in the
i
th station(We have to arrive at thei
th station in the case we have just added fuel forj - 1
times before, that is:dp[i - 1][j - 1] >= stations[i - 1][0]
):dp[i][j] = dp[i - 1][j - 1] + stations[i - 1][1]
.
dp[i][j]
is the maximum value of the two values.
Greedy algorithm Link to heading
It is easy to see that the optimal strategy is to add fuel in the station with the most fuel. Actually, we can get fuel from the station that we passed through. For each time we can’t get to the next station or destination, we get fuel from the station with the most fuel that we passed through but didn’t get fuel from, until we get to the next station or destination or there is no station we can get fuel from.
Code Link to heading
Dynamic programming Link to heading
class Solution {
public:
int minRefuelStops(int target, int startFuel, vector<vector<int>> &stations) {
int n = stations.size();
if (n == 0) {
if (startFuel >= target)
return 0;
return -1;
}
vector<vector<long long>> dp(n + 1, vector<long long>(n + 1, 0));
dp[0][0] = startFuel;
for (int i = 1; i <= n; i++) {
dp[i][0] = stations[i - 1][0] <= startFuel ? startFuel : 0;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
// We have to arrive at the `i`th station in the case we have just added fuel for `j - 1` times before,
if (dp[i - 1][j - 1] >= stations[i - 1][0])
dp[i][j] = std::max(dp[i - 1][j], dp[i - 1][j - 1] + stations[i - 1][1]);
else
dp[i][j] = dp[i - 1][j];
}
}
int res = 600;
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= i; j++) {
if (dp[i][j] >= target)
res = std::min(res, j);
}
}
return res >= 600 ? -1 : res;
}
};
Greedy algorithm Link to heading
class Solution {
public:
int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) {
int n = stations.size();
if (n == 0) {
if (startFuel >= target)
return 0;
return -1;
}
if (startFuel < stations[0][0])
return -1;
int res = 0;
auto cmp = [&](vector<int> &v1, vector<int> &v2){
return v1[1] <= v2[1];
};
priority_queue<vector<int>, vector<vector<int>>, decltype(cmp)> pq(cmp); // heap top is the station with the most fuel
pq.push(stations[0]);
int cur_fuel = startFuel - stations[0][0];
for (int i = 1; i < n; i++) {
while (!pq.empty() && cur_fuel < stations[i][0] - stations[i - 1][0]) { // notice the **while**, and judge if pq is empty first!
cur_fuel += pq.top()[1];
pq.pop();
res++;
}
if (cur_fuel < stations[i][0] - stations[i - 1][0]) {
return -1;
}
pq.push(stations[i]);
cur_fuel = cur_fuel - (stations[i][0] - stations[i - 1][0]);
}
while (!pq.empty() && cur_fuel < target - stations[n - 1][0]) {
cur_fuel += pq.top()[1];
res++;
pq.pop();
}
if (cur_fuel < target - stations[n - 1][0])
return -1;
return res;
}
};