题解:P13455 [GCJ 2008 Qualification] Train Timetable
AHOI_Capzera
·
·
题解
题目分析
我们需要计算两个车站分别需要的最少初始列车数量。解答本问题的关键点在于列车的复用,也就是说一列列车在完成行程并经过周转时间后,可以在同一车站执行下一次出发任务。
因此,我们希望通过复用列车以尽可能减少初始准备列车的数量。
$B$ 站初始准备的列车数量 = $\text{NB}$ - 可复用的列车数量($A\rightarrow B$ 行程到达 $B$ 站并周转后的列车)。
**贪心策略**:优先使用最早可用的列车来满足最早出发的需求。
Tip:由于出发和到达在同一天且时间为 $24$ 时制,我们可以将所有的时间转换为分钟进行计算。
### 算法分析
我们使用两个**优先级队列** `pq1`,`pq2` 维护在 $A$ 站最早可用列车时间以及在 $B$ 站最早可用列车时间。
将 $A \rightarrow B$ 行程的到达时间 + 周转时间($t$) 存入 `pq2`。
将 $B \rightarrow A$ 行程的到达时间 + 周转时间($t$) 存入 `pq1`。
再对 $A$ 站和 $B$ 站的列车以**出发时间**从小到大排序。
**$A$ 站**:遍历每个出发时间,若 `pq1` 中有可用列车(队头 $\le$ 出发时间),则复用该列车;否则增加一辆初始列车。
**$B$ 站**:遍历每个出发时间,若 `pq2` 中有可用列车(队头 $\le$ 出发时间),则复用该列车;否则增加一辆初始列车。
### 细节
**1. 时间转换**
形如 $\text{hh}:\text{mm}$ 的时间信息,我们可以利用字符跳过时间格式中的冒号
```cpp
int h1, m1, h2, m2;
char ch;
cin >> h1 >> ch >> m1 >> h2 >> ch >> m2;
```
**2. 优先级队列(最小堆)**
```cpp
priority_queue<int, vector<int>, greater<int>> pq;
```
### 代码
```cpp
#include <bits/stdc++.h>
using namespace std;
int T, t, na, nb, h1, m1, h2, m2;
int a[101], b[101];
char ch;
void solve(int test) {
priority_queue<int, vector<int>, greater<int> > pq1, pq2; // 两个最小堆维护最早完成周转的列车时间
int ca = 0, cb = 0; // 统计答案
cin >> t >> na >> nb;
for (int i = 0; i < na; i++) {
cin >> h1 >> ch >> m1 >> h2 >> ch >> m2;
a[i] = h1 * 60 + m1; // A 站出发时间, h * 60 + m 将小时制转为分钟制
pq2.push(h2 * 60 + m2 + t); // 维护到达 B 站并周转完成的最早列车
}
for (int i = 0; i < nb; i++) {
cin >> h1 >> ch >> m1 >> h2 >> ch >> m2;
b[i] = h1 * 60 + m1; // B 站出发时间
pq1.push(h2 * 60 + m2 + t); // 维护到达 A 站并周转完成的最早列车
}
sort(a, a + na), sort(b, b + nb); // 对出发时间从小到大排序
for (int i = 0; i < na; i++) {
if (pq1.size() && pq1.top() <= a[i]) { // 若有车可用(完成调度的时间 <= 出发时间)
pq1.pop(); // 使用该车
} else {
ca++; // 增加列车
}
}
for (int i = 0; i < nb; i++) {
if (pq2.size() && pq2.top() <= b[i]) {
pq2.pop();
} else {
cb++;
}
}
printf("Case #%d: %d %d\n", test, ca, cb);
}
int main() {
cin >> T;
for (int i = 1; i <= T; i++) solve(i);
return 0;
}
```
- **时间复杂度**: $\Omicron(n \log{n})
- 排序出发时间数组: \Omicron(n \log{n} + m \log{m})
- 优先级队列操作: 每个元素入队出队一次 \Omicron(\log{n}) 或 \Omicron(\log{m})
- 空间复杂度: \Omicron(n + m)
- 存储出发时间数组: \Omicron(n + m)
- 优先级队列: \Omicron(n + m)