2023美团春招4.8 后端真题和解析 第三题:水果打包

ps:题目均由网友口述提供,禁止商用。

题目名字:水果打包

小美不干外卖配送了,转行开了一家水果店。
一天她接到了一个大单,客户订购了n个水果,并且要求打包成多个果篮,一个果盛最多裝m个水果。
为了包装方便,水果按从1n编号、同一个果籃里装的水果编号必须是连续的。果篮的成本与容积成线性关系。为了估计容积,小美简单地用样本中点估计了一下。具体来说,假设一个果篮中装的最大的水果体积是u,最小的是v,那么这个果篮的成本就是k*floor((u+v)/2) +s,其中k是果篮中装入水果的个数,s是一个常数,floor(x) 是下取整函数。
客户并没有规定果篮的数量,但是希望果篮的成本越小越好,毕竟买水果就很费了。请求出小美打包这口个水果所用的最小花费。

输入描述

第一行三个正整数n,m,s
第二行n个正整数表示 a i a_i ai,表示每个水果的体积。
对于全部数据, 1 ≤ n ≤ 1 0 4 1 \leq n \leq 10^4 1n104 1 ≤ m ≤ 1 0 3 1 \leq m \leq 10^3 1m103 m ≤ n m \leq n mn 1 ≤ a i , s ≤ 1 0 4 1 \leq a_i,s \leq 10^4 1ai,s104

输出描述

输出一个整数表示答案。

样例

输入:
6 4 3
1 4 5 1 4 1

输出:
21

思路:

动态规划来解决问题。定义 d p [ i ] dp[i] dp[i] 表示处理前 i i i 个水果时所需的最小花费。我们需要计算 d p [ n ] dp[n] dp[n],即处理所有水果所需的最小花费:
首先,初始化 DP 数组,将所有 dp[i] 设置为 Integer.MAX_VALUE,表示最初没有找到任何合适的解决方案。我们将 dp[0] 设置为 0,因为没有水果时的花费为 0

对于每个水果 i1n),我们需要找到一个最优解。我们将尝试将前 i 个水果放入连续的果篮,每个果篮中的水果数量不能超过 m

我们将从水果 i 开始,向前查找 jji-10),并检查 ij 之间的水果数量是否不超过 m。如果不超过 m,则我们可以将这些水果放入一个果篮中。

对于每个可能的 j,我们需要计算这个果篮的成本。这可以通过找到这个范围内的最小体积和最大体积的水果,然后根据公式 ((maxVolume + minVolume) / 2) * (i - j) + s 来计算。

在计算了当前果篮的成本之后,我们可以将它与已经找到的解决方案(在 dp[j] 中存储)结合起来,然后更新 dp[i] 为这两者之和的较小值。这意味着我们正在寻找在包含当前果篮的情况下的最小花费。

在完成所有 i 的迭代之后,dp[n] 将包含处理所有水果所需的最小花费。

这样的话确保了同一个果篮中装的水果是连续的,并且每个果篮中的水果数量不超过 m

代码

C++版本

#include 
#include 
#include 
#include 

using namespace std;

int minCostToPackFruits(int n, int m, int s, vector<int>& volumes) {
    vector<int> dp(n + 1, INT_MAX);
    dp[0] = 0;

    for (int i = 1; i <= n; i++) {
        int minVolume = volumes[i - 1];
        int maxVolume = volumes[i - 1];
        for (int j = i - 1; j >= 0 && (i - j) <= m; j--) {
            minVolume = min(minVolume, volumes[j]);
            maxVolume = max(maxVolume, volumes[j]);
            int cost = ((maxVolume + minVolume) / 2) * (i - j) + s;
            dp[i] = min(dp[i], dp[j] + cost);
        }
    }

    return dp[n];
}

int main() {
    int n, m, s;
    cin >> n >> m >> s;
    vector<int> volumes(n);
    for (int i = 0; i < n; i++) {
        cin >> volumes[i];
    }
    cout << minCostToPackFruits(n, m, s, volumes) << endl;
    return 0;
}

Java版本

import java.util.Scanner;

public class Main {
    public static int minCostToPackFruits(int n, int m, int s, int[] volumes) {
        int[] dp = new int[n + 1];
        for (int i = 0; i <= n; i++) {
            dp[i] = Integer.MAX_VALUE;
        }
        dp[0] = 0;

        for (int i = 1; i <= n; i++) {
            int minVolume = volumes[i - 1];
            int maxVolume = volumes[i - 1];
            for (int j = i - 1; j >= 0 && (i - j) <= m; j--) {
                minVolume = Math.min(minVolume, volumes[j]);
                maxVolume = Math.max(maxVolume, volumes[j]);
                int cost = ((maxVolume + minVolume) / 2) * (i - j) + s;
                dp[i] = Math.min(dp[i], dp[j] + cost);
            }
        }

        return dp[n];
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        int s = scanner.nextInt();
        int[] volumes = new int[n];
        for(int i = 0; i < n; i++) {
            volumes[i] = scanner.nextInt();
        }
        System.out.println(minCostToPackFruits(n, m, s, volumes));
    }
}

Python 版本

def minCostToPackFruits(n: int, m: int, s: int, volumes: List[int]) -> int:
    dp = [float('inf')] * (n + 1)
    dp[0] = 0

    for i in range(1, n + 1):
        minVolume = volumes[i - 1]
        maxVolume = volumes[i - 1]
        for j in range(i - 1, -1, -1):
            if i - j > m:
                break
            minVolume = min(minVolume, volumes[j])
            maxVolume = max(maxVolume, volumes[j])
            cost = ((maxVolume + minVolume) // 2) * (i - j) + s
            dp[i] = min(dp[i], dp[j] + cost)

    return dp[n]

if __name__ == '__main__':
    n, m, s = map(int, input().split())
    volumes = list(map(int, input().split()))
    print(minCostToPackFruits(n, m, s, volumes))

你可能感兴趣的:(#,C++,#,笔试,ACM,c++,python,java,算法)