题解:洛谷 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
【核心思想】
-
问题分析:给定 \(N\) 周的生产计划,每周生产一台机器成本为 \(C_i\),若提前生产则需每周支付 \(S\) 元保养费。每周需交付 \(Y_i\) 台机器,可用当周生产或之前存货交付。求完成所有订单的最小总代价。这是一个贪心/动态维护最小成本问题,关键在于每周决策时比较"提前生产 + 保养累积"与"当周生产"哪种更优。
-
算法选择:
- 贪心策略:每周维护当前最低单位成本 \(minn\),该成本为"之前某周提前生产并保养至今"与"当周生产"的较小值
- 滚动更新:\(minn = \min(minn + S,\ C_i)\),表示上周最低成本叠加一周保养费后,与本周生产成本的比较
-
关键步骤:
- 初始化:读入 \(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\)
-
时间/空间复杂度:
- 时间复杂度:\(O(N)\),每周 \(O(1)\) 计算
- 空间复杂度:\(O(1)\),仅需维护 \(minn\) 和 \(ans\)
-
贪心滚动最小值的核心思想:
- 无后效性:每周的最低成本决策仅依赖上周的最低成本,与具体哪周生产无关
- 保养费累积:提前生产 \(k\) 周的成本 = 原生产成本 + \(k \times S\),通过 \(minn + S\) 逐周自然累积
- 局部最优即全局最优:每周选择最低成本生产,由于机器同质且保养费线性,不存在跨周批量生产的更优策略
- 适用于"时间序列上的成本比较 + 线性累积费用"类问题,核心是维护滚动最小值
【解题思路】

【算法标签】
普及- #贪心
【代码详解】
#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
浙公网安备 33010602011771号