题解:AtCoder AT_awc0125_a Warehouse Package Inspection
【题目来源】
AtCoder:A - Warehouse Package Inspection
【题目描述】
高橋负责检查一个大仓库中的货物。仓库里 \(N\) 个货架排成一条直线,按顺序编号为 \(1\) 到 \(N\)。从货架 \(i\) 移动到货架 \(j\) 需要 \(|i - j| \times D\) 分钟,其中 \(D\) 是一个正整数,表示相邻货架之间的移动时间(单位:分钟)。
每个货架上都有需要检查的货物,检查货架 \(i\) 上的货物需要 \(T_i\) 分钟。检查必须在货架前进行,不能在移动过程中进行。此外,高橋必须完成当前货架的检查后才能开始移动去下一个货架;检查和移动不能同时进行。虽然他可能会在移动过程中经过其他货架,但仅仅经过不算作检查。要检查它们,他必须再次移动到该货架并停下。
高橋最初在货架 \(S\) 前面。他可以自由选择先检查哪个货架。高橋从货架 \(S\) 前面移动到第一个要检查的货架,并在那里进行检查。如果他选择先检查货架 \(S\),他可以立即开始检查,移动时间为 \(0\) 分钟。
高橋必须恰好检查所有 \(N\) 个货架一次。他检查货架的顺序可以自由选择。一旦最后一个货架的检查完成,工作即结束,他不需要返回起始位置。
求完成所有货架货物检查所需的最短总时间(所有移动时间与所有检查时间之和)。
【输入】
\(N\) \(D\) \(S\)
\(T_1\) \(T_2\) \(\ldots\) \(T_N\)
- The first line contains three space-separated integers: \(N\), the number of shelves; \(D\), the travel time between adjacent shelves; and \(S\), the starting shelf number.
- The second line contains \(N\) space-separated integers \(T_1, T_2, \ldots, T_N\), representing the time required to inspect the goods on each shelf.
【输出】
Print the minimum total time (travel time + inspection time) to inspect the goods on all shelves exactly once in a single line.
【输入样例】
4 2 2
3 1 4 2
【输出样例】
18
【核心思想】
-
问题分析:给定 \(N\) 个排成直线的货架,起始位置为货架 \(S\),检查货架 \(i\) 需 \(T_i\) 分钟,相邻货架移动耗时 \(D\)。要求恰好检查所有 \(N\) 个货架一次,求移动时间 + 检查时间的最小值。检查时间总和固定,因此问题转化为最小化移动时间。
-
算法选择:
- 贪心策略:从起始点 \(S\) 出发,先走向较近的端点(\(1\) 或 \(N\)),再一路走向另一端点
- 关键观察:要覆盖 \([1, N]\) 所有点,最优路径是"从 \(S\) 到一端,再到另一端"的连续遍历,避免来回折返
-
关键步骤:
- 固定成本累加:
ans = ΣT_i,检查时间与顺序无关,直接累加 - 计算最优移动路径:
- 到较近端点的距离:
tmp = min(S - 1, N - S) - 从 \(S\) 先到较近端点,耗时
tmp × D - 再从该端点走到另一端点,需经过 \(N - 1\) 个间隔,耗时
(N - 1) × D
- 到较近端点的距离:
- 总移动时间:
tmp × D + (N - 1) × D,即ans += tmp * d + (n - 1) * d
- 固定成本累加:
-
时间/空间复杂度:
- 时间复杂度:\(O(N)\),读入 \(N\) 个检查时间并累加
- 空间复杂度:\(O(N)\),存储检查时间数组(可优化至 \(O(1)\))
-
贪心策略的核心思想:
- 端点覆盖必然性:要检查所有货架,路径必须覆盖区间 \([1, N]\),因此至少需要从一端走到另一端,基础移动距离为 \(N - 1\)
- 起始点偏移优化:从 \(S\) 出发,先向较近端点移动可减少"回头路"——若先走远端点,会多走 \(|S - \text{远端}| - |S - \text{近端}|\) 的重复距离
- 无折返最优:直线上一维覆盖问题,不折返的路径总长度最小,等价于"从 \(S\) 出发的区间覆盖"
- 检查时间独立性:\(ΣT_i\) 为常数,不影响路径选择,只需优化移动距离
- 适用于一维坐标上的遍历覆盖问题,核心在于消除冗余往返
【算法标签】
贪心
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long // 将int定义为long long,避免总时间计算溢出
const int N = 1000005; // 定义数组最大容量为1000005
int n, d, s, ans; // n为货架数量,d为相邻货架移动时间,s为起始货架编号,ans记录最短总时间
int a[N]; // a[i]表示检查货架i所需的时间
signed main() // 使用signed main配合#define int long long
{
cin >> n >> d >> s; // 读入货架数n、相邻移动时间d、起始货架s
for (int i = 1; i <= n; i++) // 读入每个货架的检查时间
{
cin >> a[i];
ans += a[i]; // 累加所有货架的检查时间(检查时间是固定的,与顺序无关)
}
// 计算最优策略下的移动时间:
// 策略:从s出发,先走到较近的端点(1或n),然后一路走到另一端点
// 这样只需走一次"回头路"(从s到较近端点),其余都是单向移动
// tmp:从起始货架s到较近端点的距离(到1的距离为s-1,到n的距离为n-s)
int tmp = min(s - 1, n - s); // 取到左端点(s-1)和右端点(n-s)的较小值
ans += tmp * d; // 加上从s到较近端点的移动时间
// 从一端走到另一端需要经过n-1个相邻间隔
ans += (n - 1) * d; // 加上从一端走到另一端的移动时间
cout << ans << endl; // 输出最短总时间(检查时间+移动时间)
return 0;
}
【运行结果】
4 2 2
3 1 4 2
18
浙公网安备 33010602011771号