题解:学而思编程 牛奶供应

【题目来源】

学而思编程:牛奶供应

【题目描述】

小猴经营了一家牧场生产牛奶,接下来 \(n\) 天时间里,每天都有订单,其中第 \(i\) 天,必须发出 \(a_i\) 箱牛奶。生产牛奶的成本来自于两方面:

(1)材料费,原料价格每天都会变化,如果选择在第 \(i\) 天生产牛奶,需要为每箱牛奶支付 \(c_i\) 元的材料费。

(2)存储费,如果原材料成本上涨,可以提前把牛奶做好,放在冷库里保存,但需要支付仓储费,一箱牛奶存放一天的成本是 \(s\) 元。

牧场产量没有上限,可以在任何一天生产处任意多数量的牛奶,冷库的容量也是无限大的,假设牛奶可以存放任意长的时间。请问,为了满足这些订单的要求,小猴应该如何规划每天的产量,又如何存储,才能把总成本控制到最小?

【输入】

第一行两个整数 \(n\)\(s\)

第二行到第 \(n+1\) 行:第 \(i+1\) 行有两个整数 \(c_i\)\(a_i\)

【输出】

一行一个整数,表示为了满足所有订单的最小总成本。

【输入样例】

3 10
100 5
200 5
90 20

【输出样例】

2850

【核心思想】

  1. 问题分析:给定 \(n\) 天的订单,每天必须发出 \(a_i\) 箱牛奶。每天生产材料费为 \(c_i\) 元/箱,提前生产的存储费为 \(s\) 元/箱/天。求满足所有订单的最小总成本。这是一个贪心递推 + 最小有效价格维护问题,关键在于每天决策"当天生产"还是"提前囤货",并将历史最优成本动态传递。

  2. 算法选择

    • 递推维护最小有效价格minp 表示当前满足当天需求的最小单位成本(含历史存储费摊销)
    • 贪心决策:每天比较"提前生产并存储到当天"与"当天生产"的成本,取较小值
  3. 关键步骤

    • 初始化
      • 读取 \(n\)(天数)和 \(s\)(每天每箱存储费)
      • 读取第 \(1\) 天的 \(c_1\)(材料费)和 \(a_1\)(订单量)
      • ans = c_1 \times a_1:第 \(1\) 天必须当天生产
      • minp = c_1:当前最小有效单位成本
    • 递推处理(第 \(2\) 天到第 \(n\) 天):
      • 读取当天的 \(c_i\)(材料费)和 \(a_i\)(订单量)
      • minp = \min(minp + s, c_i):比较两种策略
        • minp + s:延续之前的最优成本,加上一天的存储费
        • c_i:放弃囤货,当天重新生产
        • 取较小值作为新的最小有效单位成本
      • ans += minp \times a_i:以当前最小有效成本满足当天订单
    • 输出 ans
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n)\),每天 \(O(1)\) 计算
    • 空间复杂度:\(O(1)\),仅需常数变量,无需存储全部数据
  5. 最小有效价格递推的核心思想

    • 成本传递性:若第 \(i\) 天选择提前囤货,则第 \(i+1\) 天的单位成本为 minp + s(历史最优成本叠加存储费);这种传递具有最优子结构
    • 贪心最优性:每天独立决策"囤货"或"现产",由于存储费线性且产量无上限,不存在跨天耦合的复杂约束,局部最优即全局最优
    • 有效价格压缩minp 将"历史上所有可能的生产+存储方案"压缩为一个标量,代表当前最便宜的单位获取成本
    • 无后效性:第 \(i\) 天的决策只依赖 minp,与具体哪天生产无关,满足动态规划的最优子结构
    • 适用于"时变价格 + 线性存储成本 + 无容量限制"的库存规划问题,贪心递推可将复杂规划简化为线性扫描

【解题思路】

img/Pasted image 20260519124540.png

【算法标签】

递推

【代码详解】

#include <bits/stdc++.h>
using namespace std;
long long n, s, c, a, minp, ans;
int main()
{
    cin >> n >> s;  // 输入天数和运输成本

    // 处理第一天
    cin >> c >> a;  // 输入第一天的价格和购买数量
    ans += c * a;  // 第一天必须按当天价格购买
    minp = c;  // 记录到目前为止的最小有效价格

    for (int i = 2; i <= n; i++)  // 处理第2到第n天
    {
        cin >> c >> a;  // 输入当天的价格和购买数量

        // 更新最小有效价格:比较前一天的最小价格+运输成本 vs 当天价格
        minp = min(minp + s, c);

        // 以当前最小有效价格购买当天的数量
        ans += minp * a;
    }

    cout << ans << endl;  // 输出最小总成本
    return 0;
}

【运行结果】

3 10
100 5
200 5
90 20
2850
posted @ 2026-07-04 14:22  团爸讲算法  阅读(4)  评论(0)    收藏  举报