1 条题解

  • 0
    @ 2025-5-8 18:39:10

    题意分析

    本题描述了一个高速公路收费的场景。罗马的高速公路采用自动收费模式,其中特定的 CDVII 公路收费规则如下:每公里收费金额依据当天开始行驶的时间而定,每个入口和出口的摄像头会记录车辆的车牌号。每月会给车辆注册车主发送账单,费用包含按行驶公里数(依行驶起始时间对应的费率)计算的金额、每次行程 1 美元以及 2 美元的账户管理费。输入分为两部分,一是一行 24 个非负整数,代表一天中每个小时的收费标准(美分/公里);二是若干条车辆进出记录,每条记录包含车牌号(最多 20 个字母数字字符)、时间日期(mm:dd:hh:mm)、“enter”或“exit”标识以及进出位置(距离公路一端的公里数),所有日期在同一个月内。“enter”记录需与按时间顺序的下一个“exit”记录配对,未配对的记录将被忽略。输出要求按照车牌号的字母顺序,为每辆车输出车牌号和总费用。

    解题思路

    1. 数据读取与存储:首先读取 24 个整数,存储到数组 cost 中,作为不同时段的收费标准。接着,使用结构体 Photo 来存储每条车辆进出记录,包括车牌号、日期中的日、小时、分钟、进出标识(用 0 表示进入,1 表示离开)和位置信息。通过循环将所有记录存储到数组 p 中。
    2. 数据排序:定义比较函数 cmp,先按车牌号的字典序排序,若车牌号相同,则按日期的日、小时、分钟排序,若仍相同则按进出标识排序。使用 sort 函数对数组 p 进行排序,以便后续匹配进出记录。
    3. 费用计算:遍历排序后的数组 p,当遇到“enter”记录时,暂存该记录;当遇到“exit”记录且之前有暂存的“enter”记录,并且两者车牌号相同时,计算此次行程的费用。费用计算方式为:行程距离(离开位置与进入位置差值的绝对值)乘以进入时刻对应的每公里收费标准,再加上每次行程固定的 1 美元(100 美分)。将计算结果累加到 map 容器 m 中,m 的键为车牌号,值为总费用。
    4. 结果输出:遍历 map 容器 m,对于每个车辆,将其总费用加上每月固定的 2 美元(200 美分)账户管理费,然后以“车牌号 $总费用”的格式输出,总费用保留两位小数。

    示例代码

    /* POJ2648 ZOJ1849 CDVII */
    
    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <map>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    const int N = 24;
    int cost[N];
    const int M = 1000;
    const int L = 20;
    
    struct Photo {
        char license[L + 1];
        int d, h, m, io, dis;
    } p[M];
    
    bool cmp(const Photo& a, const Photo& b)
    {
        int eq = strcmp(a.license, b.license);
        if(eq != 0) return eq < 0;
        if(a.d != b.d) return a.d < b.d;
        if(a.h != b.h) return a.h < b.h;
        if(a.m != b.m) return a.m < b.m;
        return a.io < b.io;
    }
    
    int main()
    {
        string line;
        for(int flag = 0;; flag = 1) {
            getline(cin, line);
            if(line == "") break;
    
            if(flag) printf("\n");
    
            map<string, int> m;
    
            stringstream sin(line);
            for(int i = 0; i < N; i++) sin >> cost[i];
    
            int n = 0;
            while(getline(cin, line) && line != "") {
                char t[8];
                sscanf(line.c_str(), "%s %*d:%d:%d:%d %s %d", p[n].license, &p[n].d, &p[n].h, &p[n].m, t, &p[n].dis);
                p[n].io = t[1] == 'n' ? 0 : 1;
                n++;
            }
    
            sort(p, p + n, cmp);
    
            Photo pt;
            for(int i = 0; i < n; i++) {
                if(p[i].io == 0)
                    pt = p[i];
                else {
                    if(pt.io != -1) {
                        if(strcmp(pt.license, p[i].license) == 0)
                            m[string(pt.license)] += abs(p[i].dis - pt.dis) * cost[pt.h] + 100;
                        pt.io = -1;
                    }
                }
            }
    
            for(map<string, int>::iterator iter = m.begin(); iter != m.end(); iter++)
                printf("%s $%.2f\n", iter->first.c_str(), (iter->second + 200) / 100.0);
        }
    
        return 0;
    }
    

    注意事项

    1. 数据类型与范围:虽然本题输入数据规模未明确提示会导致整数溢出,但要注意存储费用和距离等数据时,使用合适的数据类型,避免因数据范围问题产生错误。
    2. 输入解析:使用 stringstreamsscanf 解析输入时,要确保输入格式符合要求。特别是 sscanf 中的格式字符串,要准确匹配输入的格式,否则可能导致解析错误。
    3. 排序规则cmp 函数中的排序规则要严格按照车牌号、日期、进出标识的优先级进行,确保排序结果正确,以便后续准确匹配进出记录。
    4. 费用计算与单位转换:费用计算时要注意单位统一,输入的收费标准是美分/公里,而输出的总费用是美元,需要进行正确的单位转换。同时,每次行程的 1 美元和每月的 2 美元管理费不要遗漏。
    5. 边界情况处理:要考虑输入中可能存在未配对的“enter”或“exit”记录,代码中通过合理的逻辑将这些未配对记录忽略,确保费用计算的准确性。
    • 1

    信息

    ID
    1648
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    4
    已通过
    1
    上传者