问题描述
小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
解题思路分析
数据结构选择
- 加油站信息:使用二维数组
gas_stations存储每个加油站的距离和油价。 - 动态规划表:使用二维数组
dp,其中dp[i][j]表示到达第i个加油站时油量为j的最小花费。
算法步骤
- 排序加油站:按照加油站距离起点的距离排序,如果距离相同则按油价排序。
- 移除无效加油站:移除距离大于等于终点的加油站,并在加油站列表末尾添加终点(油价为0)。
- 初始化动态规划表:初始化
dp表,所有值设为一个大数(表示不可达)。 - 初始状态:在第一个加油站时,油量为200 - 第一个加油站的距离,花费为0。
- 动态规划过程:
- 对于每个加油站
i,计算当前加油站与前一个加油站的距离dis和前一个加油站的油价price。 - 对于每个可能的油量
j,计算到达当前加油站时的最小花费。 - 更新
dp[i][j]为到达当前加油站时油量为j的最小花费。
- 对于每个加油站
- 计算最终结果:遍历到达终点时的所有可能油量,取最小花费作为结果。如果无法到达终点,返回
-1。
复杂度分析
- 时间复杂度:O(n * 400 * 400),其中
n是加油站的数量。 - 空间复杂度:O(n * 400),用于存储动态规划表。
通过上述步骤,可以有效地计算出从青海湖到景点X的最小旅行成本。
注意:
- 需要对加油站按照距离由近到远排序,删除大于终点的加油站
- 终点需要加入一个加油站,以保证最后达到了终点
代码如下:
int solution(int distance, int n, std::vector<std::vector<int>> g) {
// 按照加油站距离起点的距离排序,如果距离相同则按油价排序
sort(g.begin(), g.end(), [&](auto a, auto b) {
if (a[0] != b[0]) return a[0] < b[0];
return a[1] < b[1];
});
// 移除距离大于等于终点的加油站,并在加油站列表末尾添加终点(油价为0)
while (g.size() && g.back()[0] >= distance) g.pop_back();
g.push_back({distance, 0});
// 更新加油站数量
n = g.size();
// 初始化动态规划表,dp[i][j]表示到达第i个加油站时油量为j的最小花费
vector<vector<int>> dp(n, vector<int>(410, 1e9));
// 如果第一个加油站距离起点超过200km,则无法到达
if (g[0][0] > 200) return -1;
// 初始状态:在第一个加油站时,油量为200 - 第一个加油站的距离,花费为0
dp[0][200 - g[0][0]] = 0;
// 动态规划过程
for (int i = 1; i < n; i++) {
int dis = g[i][0] - g[i-1][0]; // 当前加油站与前一个加油站的距离
int price = g[i-1][1]; // 前一个加油站的油价
for (int j = 0; j <= 400; j++) {
for (int k = 0; j + dis - k >= 0 && j + dis <= 400; k++) {
// 更新到达当前加油站时的最小花费
dp[i][j] = min(dp[i][j], dp[i-1][j + dis - k] + k * price);
}
}
}
// 计算到达终点时的最小花费
int ans = 1e9;
for (int i = 200; i <= 400; i++) {
ans = min(ans, dp[n-1][i]);
}
if (ans == 1e9) ans = -1; // 如果无法到达终点,返回-1
return ans;
}
总结
本题要求计算从青海湖到景点X的最小旅行成本,考虑车辆的油箱容量、初始油量、每公里油耗以及沿途加油站的油价。主要思路是通过动态规划来解决这个问题。
首先,对加油站按距离排序,并移除距离大于等于终点的加油站,同时在列表末尾添加终点(油价为0)。接着,初始化一个二维动态规划表 dp,其中 dp[i][j] 表示到达第 i 个加油站时油量为 j 的最小花费。初始状态为在第一个加油站时,油量为200减去第一个加油站的距离,花费为0。
在动态规划过程中,对于每个加油站 i,计算当前加油站与前一个加油站的距离 dis 和前一个加油站的油价 price。然后,对于每个可能的油量 j,计算到达当前加油站时的最小花费,并更新 dp[i][j]。
最后,遍历到达终点时的所有可能油量,取最小花费作为结果。如果无法到达终点,返回 -1