1.题目
问题描述
小F计划从青海湖出发,前往一个遥远的景点X进行旅游。景点X可能是“敦煌”或“月牙泉”,线路的路径是唯一的。由于油价的不断上涨,小F希望尽量减少行程中的燃油成本。车辆的油箱容量为400L,在起始点租车时,车内剩余油量为 200L。每行驶 1km 消耗 1L 油。沿途设有多个加油站,小F可以在这些加油站补充燃油;此外,到达目标景点X还车的时候,需要保证车内剩余的油至少有 200L。
小F需要你帮助他计算,如果合理规划加油站的加油顺序和数量,最小化从青海湖到景点X的旅行成本(元)。
输入:
- distance:从青海湖到景点X的总距离(km),距离最远不超过 10000 km。
- n:沿途加油站的数量 (1 <= n <= 100)
- gas_stations:每个加油站的信息,包含两个非负整数 [加油站距离起始点的距离(km), 该加油站的油价(元/L)]
输出:
- 最小化从青海湖到景点X的旅行成本(元)。如果无法到达景点X,或者到达景点X还车时油料剩余不足 200L,则需要返回
1告诉小F这是不可能的任务。
测试样例
样例1:
输入:distance = 500, n = 4, gas_stations = [[100, 1], [200, 30], [400, 40], [300, 20]]
输出:
4300
样例2:
输入:distance = 1000, n = 3, gas_stations = [[300, 25], [600, 35], [900, 5]]
输出:
-1
样例3:
输入:distance = 200, n = 2, gas_stations = [[100, 50], [150, 45]]
输出:
9000
样例4:
输入:distance = 700, n = 5, gas_stations = [[100, 10], [200, 20], [300, 30], [400, 40], [600, 15]]
输出:
9500
样例5:
输入:distance = 50, n = 1, gas_stations = [[25, 100]]
输出:
5000
2.思路
初步分析
起始点租车时,车内剩余油量为 200L。每行驶 1km 消耗 1L 油。到达目标景点X还车的时候,需要保证车内剩余的油至少有 200L。所以沿途中需要加油的量和distance的值相等。
最好的情况是在最便宜的加油站买够需要的油,如果做不到,可以在其他车站买油,足够撑到便宜的油站即可。
样例1:
输入:distance = 500, n = 4, gas_stations = [[100, 1], [200, 30], [400, 40], [300, 20]]
输出:
4300
先将gas_stations按距离排序:[[100, 1], [200, 30], [300, 20], [400, 40]]。
最好的情况是在最便宜的加油站买够500L:
在[100, 1]加油站时,油箱空余300L,此时花费1*300=300元;
在[200, 30]加油站时,油箱内的油足够开到下一个加油站,此处不加油;
在 [300, 20]加油站,油箱空余200L,这个加油站是第二便宜的加油站,所以在此加满油,花费200*20=4000元,此时已经加够500L油,最小花费300+4000=4300元。
样例2:
输入:distance = 1000, n = 3, gas_stations = [[300, 25], [600, 35], [900, 5]]
输出:
-1
开不到第一个加油站就没油了,返回-1。
样例3:
输入:distance = 200, n = 2, gas_stations = [[100, 50], [150, 45]]
输出:
9000
优先在[150, 45]加油,油箱里的油足够开到这个油站,花费45*200=9000元
样例4:
输入:distance = 700, n = 5, gas_stations = [[100, 10], [200, 20], [300, 30], [400, 40], [600, 15]]
输出:
9500
在[100, 10]加300L油,花费300*10=3000元
在[200, 20]加100L油,花费100*20=2000元
在[600, 15]加300L油,花费300*15=4500元
总计9500元
样例5:
输入:distance = 50, n = 1, gas_stations = [[25, 100]]
输出:
5000
50*100=5000元
动态规划
定义 dp[i][j] 表示在第 i 个加油站加油后,油箱内有 j L油时的最小花费。初始状态是 dp[0][200] = 0,即在起始点有200L油且花费为0。然后逐步计算每个加油站的最优加油策略。
3.代码
不用动态规划有点写不下去
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int solution(int distance, int n,
std::vector<std::vector<int>> gas_stations) {
// Please write your code here
// 加油站按距离排序
sort(gas_stations.begin(), gas_stations.end(), [](const vector<int>& a, const vector<int>& b){
return a[0] < b[0];
});
// for (const auto& row : gas_stations) {
// for (int val : row) {
// cout << val << " ";
// }
// cout << "\n";
// }
// 到第一个加油站的距离大于200,如果无法到达景点X
if (gas_stations[0][0] > 200) {
return -1;
}
// 如果加油站间距大于400, 无法到达景点X
for (int i = 0; i < n - 1; i++) {
if ((gas_stations[i + 1][0] - gas_stations[i][0]) > 400) {
return -1;
}
}
// 加油站按价格排序
std::vector<std::vector<int>> gas_stations_value = gas_stations;
sort(gas_stations_value.begin(), gas_stations_value.end(), [](const vector<int>& a, const vector<int>& b){
return a[1] < b[1];
});
int cur_gas = 200; //当前油箱中的油量
int cost = 0; //花费
vector<int> cheapest = gas_stations_value[0]; // 指向当前最便宜的油站
// 按照距离从近到远遍历加油站
for (auto it = gas_stations.begin(); it != gas_stations.end(); ++it) {
// 更新油量
if (it == gas_stations.begin()) {
cur_gas = gas_stations[0][0];
} else {
cur_gas =
}
// 如果走到了最便宜的油站,加满
if (it == std::find(gas_stations.begin(), gas_stations.end(), cheapest)) { // 正确
}
}
return -1;
}
int main() {
std::vector<std::vector<int>> gasStations1 = {
{100, 1}, {200, 30}, {400, 40}, {300, 20}};
std::vector<std::vector<int>> gasStations2 = {
{100, 999}, {150, 888}, {200, 777}, {300, 999},
{400, 1009}, {450, 1019}, {500, 1399}};
std::vector<std::vector<int>> gasStations3 = {{101}, {100, 100}, {102, 1}};
std::vector<std::vector<int>> gasStations4 = {
{34, 1}, {105, 9}, {9, 10}, {134, 66}, {215, 90},
{999, 1999}, {49, 0}, {10, 1999}, {200, 2}, {300, 500},
{12, 34}, {1, 23}, {46, 20}, {80, 12}, {1, 1999},
{90, 33}, {101, 23}, {34, 88}, {103, 0}, {1, 1}};
std::cout << (solution(500, 4, gasStations1) == 4300) << std::endl;
std::cout << (solution(500, 7, gasStations2) == 410700) << std::endl;
std::cout << (solution(500, 3, gasStations3) == -1) << std::endl;
std::cout << (solution(100, 20, gasStations4) == 0) << std::endl;
std::cout << (solution(100, 0, std::vector<std::vector<int>>{}) ==
-1)
<< std::endl;
return 0;
}
动态规划:
import sys
def solution(distance, n, gas_stations):
# Please write your code here
maxCapacity = 400
inf = sys.maxsize
# 按照加油站位置升序排序
gas_stations.sort(key=lambda x: x[0])
# 计算每个加油站之间的距离
dis = [gas_stations[0][0]] # 初始化时只有第一个加油站的距离
for i in range(1, n):
dis.append(gas_stations[i][0] - gas_stations[i - 1][0])
# 初始化 dp 数组,dp[i][j] 表示在第 i 个加油站加油后,油箱内有 j L油时的最小花费
dp = [[inf] * (maxCapacity + 1) for _ in range(n + 2)]
dp[0][200] = 0
# 动态规划计算最小花费
for i in range(1, n + 1):
for j in range(maxCapacity + 1): # 当前站剩余油量
for k in range(maxCapacity + 1): # 前一站剩余油量
# 条件:加油后的油量合法,并能支撑到当前站
if j + dis[i - 1] - k >= 0 and k >= dis[i - 1]:
dp[i][j] = min(dp[i][j], dp[i-1][k] + (j + dis[i-1] - k) * gas_stations[i - 1][1])
# 计算到达终点时的剩余油量需求
remaining_fuel = 200 + distance - gas_stations[n - 1][0]
if remaining_fuel > maxCapacity or remaining_fuel < 0:
return -1
# 从剩余油量需求到最大油量,找出最小花费
result = inf
for j in range(remaining_fuel, maxCapacity + 1):
result = min(result, dp[n][j])
# 如果结果仍然是 inf,说明无法到达终点
if result == inf:
return -1
return result
j + dis[i - 1] - k >= 0
- 假设从上一个站点到当前站点需要加油
x,则有: k−dis[i−1]+x=j - 整理得: x=j+dis[i−1]−k
- 因为加油量
x必须大于等于 0,得出条件: j+dis[i−1]−k≥0
4.参考资料
青训营刷题日记6| 豆包MarsCode AI刷题优化青海湖至景点X的租车路线成本 在现代生活中,随着油价的不断上涨,出 - 掘金