PAT甲级刷题记录——1095 Cars on Campus (30分)

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_numberis a string of 7 English capital letters or 1-digit numbers; hh:mm:ssrepresents the time point in a day by hour:minute:second, with the earliest time being 00:00:00and the latest 23:59:59; and statusis either inor out.

Note that all times will be within a single day. Each inrecord is paired with the chronologically next record for the same car provided it is an outrecord. Any inrecords that are not paired with an outrecord are ignored, as are outrecords not paired with an inrecord. It is guaranteed that at least one car is well paired in the input, and no car is both inand outat 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 ascending 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

思路

这题没有完全AC哈,只拿了27分,打算先放一会不做了(从昨天下午做到了今天中午,修修补补,还是错了一个测试点【4】)。代码都写了注释,没事干的同学可以看一看,虽然并不是正确答案……
等过几天改了之后完全AC了再修改叭(逃)
~

2020.05.07 13:13】我终于过了T T,原来是我的时间函数计算有问题(这也能AC五个测试点??我是没想到的),原因在于计算两个时间相加的时候:h_result = h_a+h_b;,这里写赋值号的话,那么如果上有进位,就不会进到上面去,因此,应该改成h_result += h_a+h_b;,这样的话,就算有进位也没事,因为是累加上去的,而不是赋值(赋值的话会覆盖掉之前进位累加上去的1)。

这里说一下这题的大意:

  1. 首先第一行N是代表给出的N组数据(汽车进入in,或者开出out),K是代表要查询的时刻个数(K个时刻待查询);
  2. 然后就是给出N行的数据,每行有车牌号、时刻、以及进入或者开出的状态,共三个参量;
  3. 最后就是给出K个时刻,让你输出当前时刻校园里有几辆车(查询的时刻是任意的,和汽车开入开出的时刻并没什么关联);
  4. 最后一行要输出所有汽车呆的最久的时间,以及对应的汽车车牌(注意,这里是一天中呆的最久的时间,比如JH007BD,反复开入开出了两次,所以,它呆的时间要把两段时间都加上,而不是一段时间),且汽车车牌要按字母序升序输出(这个我的代码应该还可以优化一下,因为存在map里的话,以汽车车牌作为key值,本身就是字母序,应该遍历的时候直接输出即可,不用再放在vector里再排序输出了~)。

这题的想法还是很简单的,但是要处理的东西很多,很繁琐,所以就要花一点时间(我写了一个晚上+一个上午+一个中午……),首先,需要把题目给出的所有信息读入,然后对这些信息排个序,优先车牌字母序,其次是时间,这样的话,排完就能做到一个车牌号对应一块内容,每一块内容呢,又是按时间升序排序的~

然后就是筛选有用信息,因为题目说了,需要in和out配对才能算一组有效信息,因此,只有当当前的i和下一个i+1的车牌号相同,且当前的i的状态是in,以及i+1的状态是out时,这两组才能算作有效信息,于是放入Valid数组里(存放筛选后的有效信息,我这里一开始是把无效信息直接删了,后来发现这是不对的,虽然我也不知道哪儿不对……但就是错了一个测试点,分成两个数组分开放马上就AC了一个测试点……),同时,计算当前车牌号对应的停留时间长度(这里最好用map,这样的话string就正好映射一个时间)。

然后再对Valid数组按时间升序排列,这样就能得到一天中,从早到晚,汽车进出校园的时刻表了。于是,遍历Valid数组,计算当前时刻校园内的汽车数量(我这里还是用了一个map,不同于上一个的是,这里是时间映射汽车数量,因为时间我是用hh:mm:ss的方式表示的,所以是string->int)。计算汽车数量的方式很简单,只要碰到in,就cnt++,然后把它放入自己设置的map里,碰到out,就cnt–,然后再把它放入自己写的map里。

最后就是查询啦,这里的话要提一点,最好计算汽车数量和查询分开来做,先把每个时刻的汽车数量预处理好,再去对每个查询的时刻进行计算,否则会出现一些小问题(我一开始就是一边计算汽车数量,一边判断查询的时刻,后来发现这么做的话,如果时刻表里的相邻两条时刻之间有多次查询的话,那么我这么算是错的)。另外,因为查询的时刻也是按升序排列的,所以最好把迭代器it放在循环最外面,这样的话就不用每次从头开始遍历map了(如果每次从头开始遍历map,肯定会超时)。

查询的时候要处理三个问题:

  • 当前查询的时刻比it指向的时刻要小,那么这个时候很简单,只要让it回退一格,输出上一条时刻的汽车数量即可~不过这里要分个情况,如果it此时本身指向的是第一条信息,查询的时刻还要比它小的话,就直接输出0,否则就会越界啦;
  • 当前查询的时刻等于it指向的时刻,这个时候最简单,直接输出当前it指向的汽车数量即可~
  • 如果循环结束之后,当前查询的时刻仍然大于it指向的时刻,就说明此时查询的时刻是最晚时间,把it回退一格(因为此时it指向的是end(),而end()是map最后一个元素的下一个地址),输出最后一条时刻的汽车数量即可~

至于怎么找到停留最长时间和对应的车牌号就很简单啦,这里就不多说了,具体看代码叭~

代码

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
struct car{
    string plate_number, time, status;
    car(){
        plate_number.clear();
        time = "00:00:00";
        status.clear();
    }
};
struct info{
    string TimeofDuration;
    info(){
        TimeofDuration = "00:00:00";
    }
};
vector<car> List, Valid;//List用来存放原始数据,Valid用来存放有效数据
vector<string> LongestCars;//存放停留最长时间的车牌号
map<string, info> CarsInfo;//每个车牌号对应自己的停留总时间
map<string, int> num;//每个时刻对应的汽车数量
string addTime(string a, string b){//求时间a+时间b的和
    string result;
    int h_a = stoi(a.substr(0,2));
    int m_a = stoi(a.substr(3,2));
    int s_a = stoi(a.substr(6,2));
    int h_b = stoi(b.substr(0,2));
    int m_b = stoi(b.substr(3,2));
    int s_b = stoi(b.substr(6,2));
    int h_result = 0, m_result = 0, s_result = 0;
    if(s_a+s_b>=60){
        s_result = s_a+s_b-60;
        m_result += 1;
    }
    else s_result = s_a + s_b;
    if(m_a+m_b>=60){
        m_result += m_a+m_b-60;
        h_result += 1;
    }
    else m_result += m_a+m_b;
    h_result = h_a+h_b;
    string hh = to_string(h_result);
    string mm = to_string(m_result);
    string ss = to_string(s_result);
    while(hh.length()<2){
        hh.insert(0, "0");
    }
    while(mm.length()<2){
        mm.insert(0, "0");
    }
    while(ss.length()<2){
        ss.insert(0, "0");
    }
    result = hh+":"+mm+":"+ss;
    return result;
}
string calculateTime(string s, string e){//求e-s的时间差
    string result;
    int h_s = stoi(s.substr(0,2));
    int m_s = stoi(s.substr(3,2));
    int s_s = stoi(s.substr(6,2));
    int h_e = stoi(e.substr(0,2));
    int m_e = stoi(e.substr(3,2));
    int s_e = stoi(e.substr(6,2));
    int h_result = 0, m_result = 0, s_result = 0;
    if(s_e-s_s<0){
        s_e += 60;
        m_e -= 1;
        s_result = s_e - s_s;
    }
    else s_result = s_e - s_s;
    if(m_e-m_s<0){
        m_e += 60;
        h_e -= 1;
        m_result = m_e - m_s;
    }
    else m_result = m_e - m_s;
    h_result = h_e - h_s;
    string hh = to_string(h_result);
    string mm = to_string(m_result);
    string ss = to_string(s_result);
    while(hh.length()<2){
        hh.insert(0, "0");
    }
    while(mm.length()<2){
        mm.insert(0, "0");
    }
    while(ss.length()<2){
        ss.insert(0, "0");
    }
    result = hh+":"+mm+":"+ss;
    return result;
}
bool cmp2(car a, car b){//按时间排序
    return a.time<b.time;
}
bool cmp(car a, car b){
    if(a.plate_number!=b.plate_number) return a.plate_number<b.plate_number;
    else return a.time<b.time;
}
int main()
{
    int N, K;
    cin>>N>>K;
    for(int i=0;i<N;i++){
        string tmpNumber, tmpTime, tmpStatus;
        car tmp;
        cin>>tmpNumber>>tmpTime>>tmpStatus;
        tmp.plate_number = tmpNumber;
        tmp.time = tmpTime;
        tmp.status = tmpStatus;
        List.push_back(tmp);
    }
    sort(List.begin(), List.end(), cmp);//对原始数据进行排序,优先车牌号字典序,其次是时间
    for(int i=0;i<List.size();i++){
        if(i+1<List.size()&&List[i].status=="in"&&List[i+1].status=="out"&&List[i].plate_number==List[i+1].plate_number){
            //寻找有效数据:当前i和i+1为同一个车牌号,且i的状态是in,i+1的状态是out
            Valid.push_back(List[i]);
            Valid.push_back(List[i+1]);
            string tmpDuration = calculateTime(List[i].time, List[i+1].time);
            CarsInfo[List[i].plate_number].TimeofDuration = addTime(CarsInfo[List[i].plate_number].TimeofDuration, tmpDuration);
        }
    }
    sort(Valid.begin(), Valid.end(), cmp2);//对Valid数组进行时间排序
    int cnt = 0;
    for(int i=0;i<Valid.size();i++){
        if(Valid[i].status=="in"){
            cnt++;
            num[Valid[i].time] = cnt;//放入当前时刻汽车的数量
        }
        else{
            cnt--;
            num[Valid[i].time] = cnt;
        }
    }
    map<string, int>::iterator it = num.begin();
    for(int i=0;i<K;i++){
        string tmpname;
        cin>>tmpname;
        bool flag = false;
        while(it!=num.end()){
            if(it->first>tmpname&&it==num.begin()){//如果查询的时刻是最早的
                flag = true;
                cout<<0<<'\n';//说明此时一辆车也没有
                break;
            }
            else if(it->first>tmpname&&it!=num.begin()){//如果查询的时刻比it指向的时刻要小
                flag = true;
                it--;//应该取it的前一个的值
                cout<<it->second<<'\n';
                break;
            }
            else if(it->first==tmpname){//如果恰好等于此时it指向的时刻
                flag = true;
                cout<<it->second<<'\n';//那么直接输出
                break;
            }
            it++;
        }
        if(flag==false){//如果查询的时刻是最大的
            it--;//此时it应该指向了num.end(),因此要回退一位,指向最后一个元素
            cout<<it->second<<'\n';//输出最后的汽车数量
        }
    }
    string longestTime = "00:00:00";
    for(map<string, info>::iterator it = CarsInfo.begin();it!=CarsInfo.end();it++){
        if(it->second.TimeofDuration>longestTime){//更新最长时间
            longestTime = it->second.TimeofDuration;
        }
    }
    for(map<string, info>::iterator it = CarsInfo.begin();it!=CarsInfo.end();it++){
        if(it->second.TimeofDuration==longestTime){//寻找停留最长时间的车子
            LongestCars.push_back(it->first);
        }
    }
    sort(LongestCars.begin(), LongestCars.end());//对车牌号进行升序排列
    for(int i=0;i<LongestCars.size();i++){//依次输出
        if(i==0) cout<<LongestCars[i];
        else cout<<" "<<LongestCars[i];
    }
    cout<<" "<<longestTime;
    return 0;
}

你可能感兴趣的:(PAT甲级)