补给站最优花费问题
题目类型
思维题、贪心、动态规划
问题描述
小U计划进行一场从地点A到地点B的徒步旅行,旅行总共需要 M 天。为了在旅途中确保安全,小U每天都需要消耗一份食物。在路程中,小U会经过一些补给站,这些补给站分布在不同的天数上,且每个补给站的食物价格各不相同。
小U需要在这些补给站中购买食物,以确保每天都有足够的食物。现在她想知道,如何规划在不同补给站的购买策略,以使她能够花费最少的钱顺利完成这次旅行。
M:总路程所需的天数。N:路上补给站的数量。p:每个补给站的描述,包含两个数字A和B,表示第A天有一个补给站,并且该站每份食物的价格为B元。
保证第0天一定有一个补给站,并且补给站是按顺序出现的。
测试样例
样例1:
输入:
m = 5 ,n = 4 ,p = [[0, 2], [1, 3], [2, 1], [3, 2]]
输出:7
样例2:
输入:
m = 6 ,n = 5 ,p = [[0, 1], [1, 5], [2, 2], [3, 4], [5, 1]]
输出:6
样例3:
输入:
m = 4 ,n = 3 ,p = [[0, 3], [2, 2], [3, 1]]
输出:9
思路分析
- 对于这个题目,是一个最小化花费的问题,在这个情况下,在每一天应该尽可能贪心地选择花费最少的时候买入,当然包括在接下来的天数里,如果今天是最便宜的,那么也在今天买入。
- 那么现在有个问题就是,怎么在今天知道以后天数是否比较贵,怎么决定是否就在今天买,可以发现其实就是从到每一天的时候,在前面最便宜的一天买,但是注意不能在后面的天数买,因为时间还没到。
- 那么转化一下思维,就可以用一个数组来维护前缀最小值的信息,也就是到每天的时候,在今天之前里面最小的值是多少,用这个最小值来表示今天消费一个食物所需要的花费是多少。
- 这有点动态规划的思想,可以用一个dp数组来表示,注意初始化和边界情况,这里为了方便处理,就把dp数组初始化为inf,因为是为了保留最小值。那么转移方程就是:dp[i] = min(dp[i-1], dp[i])。
- 通过处理出dp数组后,遍历每一天,累加得到最后的结果。
代码分析
- 数据结构选择:
- 使用
std::map<int, int>来存储补给站的信息,也就是前面提到的dp数组,其中键是天数,值是食物的价格。 std::map可以自动排序,并且可以通过键快速查找,便于后续处理。
- 算法逻辑:
- 遍历每一天,并在每一天中找到当前最便宜的食物价格,然后累加到结果中。
- 注意是在每一天都重新计算最便宜的价格,不能考虑未来补给站的价格,因为还没到那一天。
- 具体实现:
- 可以考虑使用动态规划来优化算法。定义一个数组
dp,其中dp[i]表示在第i天结束时,小U花费的最小金额。 - 状态转移方程可以考虑从之前的某一天购买食物,直到第
i天。 - 遍历每一天时,维护一个当前最便宜的价格。
- 处理所有可能的边界条件,这里因为使用取min的形式减少了很多不必要的边界判断。
#include <iostream>
#include <vector>
#include <map>
int solution(int m, int n, std::vector<std::vector<int>> p) {
int mi = 1e9,res =0;
std::map<int, int> dp;
for(auto x : p) {
dp[x[0]] = x[1];
}
for(int i = 0; i < m; i++) {
if(dp[i] == 0) dp[i] = 1e9;
mi = std::min(mi, dp[i]);
res += mi;
}
return res;
}