题解:洛谷 P1376 机器工厂

【题目来源】

洛谷:P1376 [USACO05MAR] Yogurt factory 机器工厂 - 洛谷

【题目描述】

小 T 开办了一家机器工厂,在 \(N\) 个星期内,原材料成本和劳动力价格不断起伏,第 \(i\) 周生产一台机器需要花费 \(C_i\) 元。若没把机器卖出去,每保养一台机器,每周需要花费 \(S\) 元,这个费用不会发生变化。

机器工厂接到订单,在第 \(i\) 周需要交付 \(Y_i\) 台机器给委托人,第 \(i\) 周刚生产的机器,或者之前的存货,都可以进行交付。

请你计算出这 \(n\) 周时间内完成订单的最小代价。

【输入】

第一行输入两个整数 \(N\)\(S\),接下来 \(N\) 行每行两个数 \(C_i\)\(Y_i\)

【输出】

输出一个整数,表示最少的代价。

【输入用例】

4 5
88 200
89 400
97 300
91 500

【输出用例】

126900

【核心思想】

  1. 问题分析:给定 \(N\) 周的生产计划,每周生产一台机器成本为 \(C_i\),若提前生产则需每周支付 \(S\) 元保养费。每周需交付 \(Y_i\) 台机器,可用当周生产或之前存货交付。求完成所有订单的最小总代价。这是一个贪心/动态维护最小成本问题,关键在于每周决策时比较"提前生产 + 保养累积"与"当周生产"哪种更优。

  2. 算法选择

    • 贪心策略:每周维护当前最低单位成本 \(minn\),该成本为"之前某周提前生产并保养至今"与"当周生产"的较小值
    • 滚动更新\(minn = \min(minn + S,\ C_i)\),表示上周最低成本叠加一周保养费后,与本周生产成本的比较
  3. 关键步骤

    • 初始化:读入 \(N, S\),读入第 \(1\) 周的 \(C_1, Y_1\)
    • \(ans = C_1 \times Y_1\)\(minn = C_1\)
    • 逐周处理\(i\)\(2\)\(N\)):
      • 读入 \(C_i, Y_i\)
      • 更新最低成本:\(minn = \min(minn + S,\ C_i)\)
      • 累加本周代价:\(ans \mathrel{+}= minn \times Y_i\)
    • 输出 \(ans\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N)\),每周 \(O(1)\) 计算
    • 空间复杂度:\(O(1)\),仅需维护 \(minn\)\(ans\)
  5. 贪心滚动最小值的核心思想

    • 无后效性:每周的最低成本决策仅依赖上周的最低成本,与具体哪周生产无关
    • 保养费累积:提前生产 \(k\) 周的成本 = 原生产成本 + \(k \times S\),通过 \(minn + S\) 逐周自然累积
    • 局部最优即全局最优:每周选择最低成本生产,由于机器同质且保养费线性,不存在跨周批量生产的更优策略
    • 适用于"时间序列上的成本比较 + 线性累积费用"类问题,核心是维护滚动最小值

【解题思路】

img/Pasted image 20260519125827.png

【算法标签】

普及- #贪心

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int n, s, c, y;
long long ans;
int main()
{
    cin >> n >> s;  // 输入n和s
    cin >> c >> y;  // 输入第1周的c和y
    ans = c * y;  // 得到代价
    int minn = c;  // 定义最小花费为c,后面循环更新
    for (int i=2; i<=n; i++) {  // 从第2周遍历至n周
        cin >> c >> y;  // 输入这周的c和y
        minn = min(minn+s, c);  // 在上周最小的花费基础上增加s元保养费、本周花费中选择最小值
        ans += minn * y;  // 用最小花费乘上本周机器数量,再进行累加,得到最小代价
    }
    cout << ans << endl;  // 打印最小代价
    return 0;
}

【运行结果】

4 5
88 200
89 400
97 300
91 500
126900
posted @ 2026-08-27 11:06  团爸讲算法  阅读(4)  评论(0)    收藏  举报