在算法竞赛中,处理时间相关的题目往往需要格外小心细节。PTA天梯赛的L1-043‘阅览室’就是这样一个典型例子,它考察的不仅是基础编程能力,更是对边界条件和异常处理的把控。这道题看似简单,实则暗藏多个陷阱,许多参赛者即使思路正确,也常因细节疏忽而失分。
这道题的核心要求是统计每天的借书次数和平均阅读时间,但有几个关键约束条件需要特别注意:
最常见的错误集中在三个方面:
提示:在调试时,可以专门针对这三个方面设计测试用例,验证程序的健壮性。
状态标记是这道题的第一个关键点。我们需要准确记录每本书的借出状态,以避免重复计算或漏算。以下是实现状态标记的几种常见方法对比:
| 方法 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| 数组标记法 | 使用二维数组arr[1001][2],arr[id][0]记录状态,arr[id][1]记录时间 | 实现简单,访问速度快 | 需要预先分配固定空间 |
| 哈希表标记法 | 使用unordered_map<int, pair<bool, int>>记录状态和时间 | 空间利用率高 | 实现稍复杂,访问速度略慢 |
| 结构体数组 | 定义Book结构体包含状态和时间字段 | 代码可读性好 | 同数组标记法 |
对于竞赛场景,推荐使用数组标记法,因为:
关键实现代码片段:
c复制int arr[1001][2] = {0}; // 初始化所有书为未借出状态
if (ch == 'S') {
arr[id][0] = 1; // 标记为已借出
arr[id][1] = h * 60 + m; // 记录借出时间
} else if (ch == 'E' && arr[id][0] == 1) {
// 只有当前状态是已借出时才处理归还
count++;
sumtime += h * 60 + m - arr[id][1];
arr[id][0] = 0; // 必须重置状态!
}
时间计算是这道题的第二个关键难点。题目中的时间格式为hh:mm,需要转换为分钟数进行计算。常见的时间计算错误包括:
正确处理步骤应该是:
start = hh * 60 + mmend = hh * 60 + mmduration = end - startsumtime += durationaverage = round(1.0 * sumtime / count)注意:在C语言中,直接使用
%.0f格式化输出会自动四舍五入,相当于调用了round函数。
时间计算示例表格:
| 操作记录 | 时间字符串 | 转换后分钟数 | 时间差(分钟) |
|---|---|---|---|
| S 08:10 | 08:10 | 8*60+10=490 | - |
| E 10:00 | 10:00 | 10*60+0=600 | 600-490=110 |
| S 13:15 | 13:15 | 13*60+15=795 | - |
| E 14:30 | 14:30 | 14*60+30=870 | 870-795=75 |
基于上述分析,我们可以构建一个完整的解题框架。以下是分步骤的实现指南:
初始化阶段:
每日处理循环:
结果输出:
调试时特别建议关注以下测试用例:
code复制3
1 S 08:00
1 E 09:30
0 S 00:00
2 S 10:00
2 E 10:30
0 E 00:00
1 E 12:00
0 S 00:00
这个测试用例包含了:
在竞赛环境中,代码的简洁性和执行效率都很重要。针对这道题,可以考虑以下优化:
简洁实现示例:
c复制#include<stdio.h>
int main() {
int n, id, h, m, count, sumtime;
char ch;
int book[1001] = {0}, time[1001] = {0};
scanf("%d", &n);
while (n--) {
count = sumtime = 0;
while (scanf("%d %c %d:%d", &id, &ch, &h, &m), id) {
if (ch == 'S') {
book[id] = 1;
time[id] = h * 60 + m;
} else if (book[id]) {
count++;
sumtime += h * 60 + m - time[id];
book[id] = 0;
}
}
printf("%d %.0f\n", count, count ? 1.0 * sumtime / count : 0);
}
return 0;
}
这段代码通过:
显著提升了代码的简洁性,同时保持了良好的可读性。