2 徒步旅行中的补给问题

41 阅读1分钟

解法1:动态规划

    public static int solution(int n, int k, int[] data) {
        // Edit your code here
        // dp[i][j] => 第(i)天剩余j个补给的情况下,所需花费的最小金额。求min(dp[n][0])
        int[][] dp = new int[n + 1][k];
        for (int i = 0; i < n + 1; i++) {
            for (int j = 0; j < k; j++) {
                dp[i][j] = 99999;
            }
        }
        dp[0][0] = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= k - 1; j++) {
                // x i当天购买的补给数, x >= 0
                for (int x = Math.max(j + 2 - k, 0); x <= j + 1; x++) {
                    dp[i][j] = Math.min(dp[i][j], x * data[i - 1] + dp[i - 1][j + 1 - x]);
                }
            }
        }
        return dp[n][0];
    }

解法2:单调栈+贪心

    public static int solution(int n, int k, int[] data) {
        // Edit your code here
        Stack<Integer> stack = new Stack<>();
        int[] lessIndex = new int[n];
        for (int i = n - 1; i >= 0; i--) {
            while (!stack.isEmpty() && data[i] <= data[stack.peek()]) {
                stack.pop();
            }
            lessIndex[i] = stack.isEmpty() ? -1 : stack.peek();
            stack.push(i);
        }
        int cost = 0;
        int remain = 0;
        int i = 0;
        int buy = 0;
        int days = 0;
        while (i < n) {
            days = lessIndex[i] - i;
            if (lessIndex[i] == -1) {
                buy = Math.min(k-remain, n - i - remain);
            } else if (days >= k) {
                buy = k-remain;
            } else {
                buy = Math.max(days - remain, 0);
            }
            cost = cost + buy * data[i];
            remain = remain + buy - 1;
            i++;
        }
        return cost;
    }