补给站最优花费问题 | 豆包MarsCode AI 刷题

66 阅读3分钟

补给站最优花费问题

题目类型

思维题、贪心、动态规划

问题描述

小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数组后,遍历每一天,累加得到最后的结果。

代码分析

  1. 数据结构选择
  • 使用 std::map<int, int> 来存储补给站的信息,也就是前面提到的dp数组,其中键是天数,值是食物的价格。
  • std::map 可以自动排序,并且可以通过键快速查找,便于后续处理。
  1. 算法逻辑
  • 遍历每一天,并在每一天中找到当前最便宜的食物价格,然后累加到结果中。
  • 注意是在每一天都重新计算最便宜的价格,不能考虑未来补给站的价格,因为还没到那一天。
  1. 具体实现
  • 可以考虑使用动态规划来优化算法。定义一个数组 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;
}