• PAT甲级1016Phone Bills


    题目介绍

    • 题目链接

      https://pintia.cn/problem-sets/994805342720868352/problems/994805493648703488

    • 题目考点

      map、排序、模拟。map是简单地用了一下,排序也不难,重在模拟。

    • 题目难度

      PAT甲级25分

    • 题目大意

      • 长途电话每分钟收取一定费用,收费金额取决于拨打电话的时间。每次电话的开始时间和结束时间都会被记录,给出一系列通话记录,请生成每个月的账单。
    • 输入

      • 1行24个非负整数:00:00 - 01:00、01:00 - 02:00,以此类推一天中每个小时的收费金额(单位是cents/minute
      • N:正整数,不超过1000,通话记录的数量
      • N行通话记录:1行的内容包括客户名称(最多20个字符的字符串,不包含空格)、日期和时间(MM:dd:HH:mm)、1个词(on-lineoff-line),这些通话记录都是同一个月的。1个on-line记录与同1客户的时间顺序上的1个off-line记录配对,没有形成pair的通话记录会被忽略。输入中至少会有1个pair。假设同1客户不会有2条时间相同的记录。输入中时间的格式为24小时制。
    • 输出

      按客户名称的字母表顺序为每1个客户输出账单。对于每1个客户来说,要输出其名字、账单的月份、每条通话记录(包括开始时间、结束时间、通话分钟数、收费金额,要按时间顺序输出多条通话记录)、账单总金额

    题解

    解题思路

    • 找到pair,生成通话记录

      先根据时间排序,然后判断是否形成pair(时间顺序、同用户、onLine和offLine)

    • 计算1次通话的费用,还有总费用

      可以从0开始计算(需要先对收费金额进行处理),这样计算更容易。on-lineoff-line2个时间点,计算0点到这2个时间点一直通话的收费,取差额即为应该支付的费用。

    • 确定月份

      输出时取第1个记录的月份

    • 客户名字字典序

      map实现(也可以通过结构体排序实现)

    • Record时间序输出

      通过结构体排序实现

    • 读取输入时不一定要保存原信息

      比如时间本身是string,我们可以直接记录monthday等,把:等分隔符去除。on-lineoff-line是字符串,我们可以用bool表示。

    代码

    // Problem: PAT Advanced 1016
    // URL: https://pintia.cn/problem-sets/994805342720868352/problems/994805493648703488
    // Tags: map 排序
    
    #include <iostream>
    #include <map>
    #include <vector>
    #include <string>
    #include <algorithm>
    using namespace std;
    
    int charge[25];
    
    struct Record{
        string name;
        bool status;
        int month, day, hour, minute, time;
    
        void setStatus(string& status){
            if (status == "on-line")
                this->status = true;
            else
                this->status = false;
        }
    
        void calcTime(){ // 以月初为零点的时间
            time = day * 24 * 60 + hour * 60 + minute;
        }
    
        bool pairWith(Record& r){
            return name == r.name && status==true && r.status==false;
        }
    
        double calcCostFromZero(){
            double cost = day * 60 * charge[24] + minute * charge[hour]; // 天、分钟
            for (int i=0; i<hour; i++){ // 小时
                cost += 60 * charge[i];
            }
            return cost / 100.0; // cent换算成美元
        }
    
        void print(){
            printf("%02d:%02d:%02d ", day, hour, minute);
        }
    };
    
    bool recordCmp(Record& a, Record& b){
        return a.name == b.name ? a.time < b.time : a.name < b.name;
    }
    
    int main()
    {
        // 读取输入并处理数据
        int n;
        for (int i=0; i<24; i++){
            scanf("%d", charge + i);
            charge[24] += charge[i]; // charge[24]是1整天都在通话时1天的收费
        }
        scanf("%d", &n);
        vector<Record> records(n);
        string status;
        for (int i=0; i<n; i++){
            cin >> records[i].name;
            scanf("%d:%d:%d:%d", &records[i].month, &records[i].day, &records[i].hour, &records[i].minute);
            cin >> status;
            records[i].setStatus(status);
            records[i].calcTime(); // 以月初为0点
        }
        sort(records.begin(), records.end(), recordCmp);
        // 为每个客户记录订单
        map<string, vector<Record>> customers;
        for (int i=1; i<n; i++){
            if (records[i-1].pairWith(records[i])){
                customers[records[i].name].push_back(records[i-1]);
                customers[records[i].name].push_back(records[i]);
            }
        }
    
        // 输出结果
        for(auto customer=customers.begin(); customer!=customers.end(); customer++){
            cout << customer->first;
            records = customer->second;
            printf(" %02d
    ", records[0].month);
            double totalCost = 0, cost;
            for (int i=1; i<records.size(); i+=2){
                cost = records[i].calcCostFromZero() - records[i-1].calcCostFromZero();
                totalCost += cost;
                records[i-1].print();
                records[i].print();
                printf("%d ", records[i].time - records[i-1].time);
                printf("$%.02f
    ", cost);
            }
            printf("Total amount: $%.02f
    ", totalCost);
        }
    
        return 0;
    }
    

    参考链接


    Github(github.com):@chouxianyu

    Github Pages(github.io):@臭咸鱼

    知乎(zhihu.com):@臭咸鱼

    博客园(cnblogs.com):@臭咸鱼

    B站(bilibili.com):@绝版臭咸鱼

    微信公众号:@臭咸鱼

    转载请注明出处,欢迎讨论和交流!


  • 相关阅读:
    2-3树
    B树
    负载均衡的算法种类
    String源码分析
    实现一个List集合中的某个元素的求和
    就是通过事件方法,在window.loaction.href里追加了参数字符串
    九大内置对象及四个域对象的总结
    BigDecimal add方法问题:调用add后,求和结果没变
    java中List元素移除元素的那些坑
    Java序列化和反序列化,你该知道得更多
  • 原文地址:https://www.cnblogs.com/chouxianyu/p/14361390.html
Copyright © 2020-2023  润新知