豆包38 补给站最优花费问题

107 阅读3分钟

问题描述

小U计划进行一场从地点A到地点B的徒步旅行,旅行总共需要 M 天。为了在旅途中确保安全,小U每天都需要消耗一份食物。在路程中,小U会经过一些补给站,这些补给站分布在不同的天数上,且每个补给站的食物价格各不相同。

小U需要在这些补给站中购买食物,以确保每天都有足够的食物。现在她想知道,如何规划在不同补给站的购买策略,以使她能够花费最少的钱顺利完成这次旅行。

  • M:总路程所需的天数。
  • N:路上补给站的数量。
  • p:每个补给站的描述,包含两个数字 A 和 B,表示第 A 天有一个补给站,并且该站每份食物的价格为 B 元。

保证第0天一定有一个补给站,并且补给站是按顺序出现的。

算法选择

dfs + 记忆化搜索

算法思路

  1. 初始化

    • 创建一个二维数组memo,用于存储动态规划的结果,其中memo[cur][food]表示在第cur天,剩余food份食物时的最小花费。
    • memo数组中的所有元素初始化为-1,表示尚未计算。
    • 创建一个HashMap,将每个补给站的天数和食物价格存储起来。
  2. 深度优先搜索(DFS)

    • 定义一个递归函数dfs(map, M, cur, food),表示在第cur天,剩余food份食物时的最小花费。
    • 如果food < 0,表示食物不足,返回一个很大的值(Integer.MAX_VALUE / 2),表示这种情况不可能发生。
    • 如果cur == M,表示旅行结束,返回0,表示不需要再购买食物。
    • 如果memo[cur][food]不等于-1,直接返回memo[cur][food]的值,表示已经计算过。
    • 如果第cur天有补给站,遍历所有可能购买的食物数量i(从0到M - cur - food),计算购买i份食物后的最小花费,并更新res
    • 如果第cur天没有补给站,直接计算不购买食物的最小花费。
  3. 返回结果

    • 最终,dfs(map, M, 0, 0)的值就是从第0天开始,剩余0份食物时的最小花费。

代码展示

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Main {
    private static int[][] memo;

    public static int solution(int m, int n, int[][] p) {
        // Edit your code here
        // 对于今天, 我可以买补给, 不买不补给
        memo = new int[m + 1][m + 1];
        for (int i = 0; i < m + 1; i++) {
            Arrays.fill(memo[i], -1);
        }
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < n; i++) {
            map.put(p[i][0], p[i][1]);
        }
        int res = dfs(map, m, 0, 0);

        return res;
    }

    public static int dfs(Map<Integer, Integer> map, int M, int cur, int food) {
        // 非法
        if (food < 0) {
            return Integer.MAX_VALUE / 2;
        }
        // 正常
        if (cur == M) {
            return 0;
        }
        if (memo[cur][food] != -1) {
            return memo[cur][food];
        }
        int res = Integer.MAX_VALUE;
        if (map.containsKey(cur)) {
            for (int i = 0; i <= (M - cur - food); i++) {
                res = Math.min(res, dfs(map, M, cur + 1, food + i - 1) + i * map.get(cur));
            }
            return memo[cur][food] = res;
        } else {
            return memo[cur][food] = dfs(map, M, cur + 1, food - 1);
        }
    }

    public static void main(String[] args) {
        // Add your test cases here

        System.out.println(solution(5, 4, new int[][] { { 0, 2 }, { 1, 3 }, { 2, 1 }, { 3, 2 } }));
    }
}