【PAT甲级】1095 Cars on Campus

本文介绍了一种校园停车管理系统的设计与实现,该系统能够处理车辆进出记录,排除无效记录,实时统计停车场内的车辆数量,并找出停车时间最长的车辆。通过时间转换和数组记录,实现了高效的车辆管理和查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Zhejiang University has 8 campuses and a lot of gates. From each gate we can collect the in/out times and the plate numbers of the cars crossing the gate. Now with all the information available, you are supposed to tell, at any specific time point, the number of cars parking on campus, and at the end of the day find the cars that have parked for the longest time period.

Input Specification:

Each input file contains one test case. Each case starts with two positive integers N (≤10​4​​), the number of records, and K (≤8×10​4​​) the number of queries. Then N lines follow, each gives a record in the format:

plate_number hh:mm:ss status

where plate_number is a string of 7 English capital letters or 1-digit numbers; hh:mm:ss represents the time point in a day by hour:minute:second, with the earliest time being 00:00:00 and the latest 23:59:59; and status is either in or out.

Note that all times will be within a single day. Each in record is paired with the chronologically next record for the same car provided it is an out record. Any in records that are not paired with an out record are ignored, as are out records not paired with an in record. It is guaranteed that at least one car is well paired in the input, and no car is both in and out at the same moment. Times are recorded using a 24-hour clock.

Then K lines of queries follow, each gives a time point in the format hh:mm:ss. Note: the queries are given in accending order of the times.

Output Specification:

For each query, output in a line the total number of cars parking on campus. The last line of output is supposed to give the plate number of the car that has parked for the longest time period, and the corresponding time length. If such a car is not unique, then output all of their plate numbers in a line in alphabetical order, separated by a space.

Sample Input:

16 7
JH007BD 18:00:01 in
ZD00001 11:30:08 out
DB8888A 13:00:00 out
ZA3Q625 23:59:50 out
ZA133CH 10:23:00 in
ZD00001 04:09:59 in
JH007BD 05:09:59 in
ZA3Q625 11:42:01 out
JH007BD 05:10:33 in
ZA3Q625 06:30:50 in
JH007BD 12:23:42 out
ZA3Q625 23:55:00 in
JH007BD 12:24:23 out
ZA133CH 17:11:22 out
JH007BD 18:07:01 out
DB8888A 06:30:50 in
05:10:00
06:30:50
11:00:00
12:23:42
14:00:00
18:00:00
23:59:00

Sample Output:

1
4
5
2
1
0
1
JH007BD ZD00001 07:20:09

题目大意

这题题目大意是给出n个车辆进入和离开记录,其中有可能有无效的记录,也就是同一辆车如果多次连续进入,取最后一次进入记录,如果连续离开,则取第一次离开的记录。然后进行k次查询,每次查询输入一个时间,然后要输出当前时间学校内有多少辆车。最后还要输出在学校内停车时间最长的车。

个人思路

这题我设立了两个结构体,一个存储出入记录,一个存储车的信息。过程是先对所有的记录按照时间顺序从前往后进行排序,然后遍历一遍排序后的数组,排除无效的记录,并且记录每辆车停的时间。这个过程中我使用了map<string,int>记录了车牌id到车子索引的映射。

  • 判断记录是否有效的方法:先初始化所有的记录为无效的。当满足某辆车子前一条记录是进来的,当前记录是离开的这个条件时,将这两个记录赋值为有效,是否有效在记录结构体中用real来表示。
  • 判断某个时间点车子数量的方法:一天时间只有24*60*60秒,所以我建立了一个86400+5大小的整型数组p_num[],存放每秒钟的车子数量。记录每秒车子数量的方法是每次车子有效进入或者离开时,计算当前的秒数,并将其存入p_num[]。最后遍历一遍p_num[],把车子数量变化不同时间点的中间时间用前一个车子变化的时间点的车子数量填满。然后查询时直接通过下标查询即可。
  • 最后的输出的停车时间最长的车子有一个坑:一辆车如果停多次,要将不同停车时间累加

然后按照停车总时间进行排序输出即可。

实现代码

#include <cstdio>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#define ll long long
#define eps 1e-8
#define INF 0x7FFFFFFF
using namespace std;
// 存储每个时间点的停车数量
const int maxn = 86405;
int p_num[maxn];
// 进出记录结构体
struct Record {
    string id;
    int hour, minute, second;
    bool status; // 1:in 0:out
    bool real; // 1:有效记录 0:无效记录
};
// 车辆记录结构体
struct Car {
    string id;
    int p_time, hour, minute, second, rec_pos;
    bool status;
};
// 对记录按照时间从小到大排序
bool cmp1(Record r1, Record r2) {
    if (r1.hour != r2.hour) return r1.hour < r2.hour;
    else if (r1.minute != r2.minute) return r1.minute < r2.minute;
    else return r1.second < r2.second;
}
// 对车辆按照停车总时间从大到小进行排序,如果相等按照车牌从小到大排序
bool cmp2(Car c1, Car c2) {
    if (c1.p_time != c2.p_time) return c1.p_time > c2.p_time;
    else return c1.id < c2.id;
}
// 将时间转化成秒数
int time2sec(int hour, int minute, int second) {
    return hour*3600 + minute*60 + second;
}
// 将秒数转换成字符串的时间
string sec2time(int s) {
    int hour, minute, second;
    hour = s / 3600;
    minute = s % 3600 / 60;
    second = s % 3600 % 60;
    char ret_str[10];
    sprintf(ret_str, "%02d:%02d:%02d", hour, minute, second);
    string ret = ret_str;
    return ret;
}

int main() {
    // 输入
    int n, k;
    cin >> n >> k;
    vector<Record>records;
    // 将记录存进records
    for (int i = 0; i < n; i ++) {
        Record r;
        cin >> r.id;
        scanf("%d:%d:%d", &r.hour, &r.minute, &r.second);
        string status;
        cin >> status;
        if (status == "in") r.status = true;
        else r.status = false;
        r.real = false;
        records.push_back(r);
    }
    // 按照时间从前往后排序
    sort(records.begin(), records.end(), cmp1);
    vector<Car>cars;
    map<string, int>idx;
    int car_cnt = 0;
    // 遍历一遍记录,排除无效记录,同时记录每辆车停的时间
    for (int i = 0; i < n; i ++) {
        Record r = records[i];
        // 新增车辆记录,并建立车牌到车辆索引的映射
        if (idx[r.id] == 0) {
            Car c;
            c.id = r.id;
            c.p_time = 0;
            c.status = 0;
            cars.push_back(c);
            idx[c.id] = ++car_cnt;
        }
        Car c = cars[idx[r.id]-1];
        // 这辆车in
        if (r.status) {
            cars[idx[r.id]-1].status = true;
        }
        // 这辆车out
        else if (!r.status && c.status) {
            // 只有一辆车出去的时候,这辆车进来的记录和出去的记录才有效
            records[c.rec_pos].real = true;
            records[i].real = true;
            int t = time2sec(r.hour, r.minute, r.second)-time2sec(c.hour, c.minute, c.second);
            cars[idx[r.id]-1].p_time += t;
            cars[idx[r.id]-1].status = false;
        }
        cars[idx[r.id]-1].rec_pos = i;
        cars[idx[r.id]-1].hour = r.hour;
        cars[idx[r.id]-1].minute = r.minute;
        cars[idx[r.id]-1].second = r.second;
    }
    // 将每一时间点的停车数求出并存入p_num[]
    memset(p_num, 0, sizeof(p_num));
    int cnt = 0;
    set<int>change_times;
    // 记录停车数改变的时间点和停车数
    for (int i = 0; i < n; i ++) {
        Record r = records[i];
        if (!r.real) continue;
        if (r.status) cnt ++;
        else cnt --;
        int change_time = time2sec(r.hour, r.minute, r.second);
        p_num[change_time] = cnt;
        change_times.insert(change_time);
    }
    // 将空白的连续时间填上数量
    for (int i = 1; i < maxn; i ++) {
        if (change_times.count(i) != 0) continue;
        if (p_num[i] == 0) p_num[i] = p_num[i-1];
    }
    // 输出
    for (int i = 0; i < k; i ++) {
        int h, m, s;
        scanf("%d:%d:%d", &h, &m, &s);
        int t = time2sec(h, m, s);
        printf("%d\n", p_num[t]);
    }
    sort(cars.begin(), cars.end(), cmp2);
    int max_p_time = cars[0].p_time;
    for (int i = 0; i < car_cnt; i ++) {
        if (max_p_time == cars[i].p_time) cout << cars[i].id << " ";
    }
    cout << sec2time(max_p_time);
    return 0;
}

总结

学习不息,继续加油

这题的代码又写得好长好难看,看看柳神的简介代码陶冶陶冶情操。https://blog.youkuaiyun.com/liuchuo/article/details/54576004

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值