「1016」Phone Bills

ENTRY

A long-distance telephone company charges its customers by the following rules:

Making a long-distance call costs a certain amount per minute, depending on the time of day when the call is made. When a customer starts connecting a long-distance call, the time will be recorded, and so will be the time when the customer hangs up the phone. Every calendar month, a bill is sent to the customer for each minute called (at a rate determined by the time of day). Your job is to prepare the bills for each month, given a set of phone call records.

Input Specification:

Each input file contains one test case. Each case has two parts: the rate structure, and the phone call records.

The rate structure consists of a line with 24 non-negative integers denoting the toll (cents/minute) from 00:00 - 01:00, the toll from 01:00 - 02:00, and so on for each hour in the day.

The next line contains a positive number N (≤1000), followed by N lines of records. Each phone call record consists of the name of the customer (string of up to 20 characters without space), the time and date (MM:dd:HH:mm), and the word on-line or off-line.

For each test case, all dates will be within a single month. Each on-line record is paired with the chronologically next record for the same customer provided it is an off-line record. Any on-line records that are not paired with an off-line record are ignored, as are off-line records not paired with an on-line record. It is guaranteed that at least one call is well paired in the input. You may assume that no two records for the same customer have the same time. Times are recorded using a 24-hour clock.

Output Specification:

For each test case, you must print a phone bill for each customer.

Bills must be printed in alphabetical order of customers’ names. For each customer, first print in a line the name of the customer and the month of the bill in the format shown by the sample. Then for each time period of a call, print in one line the beginning and ending time and date (dd:HH:mm), the lasting time (in minute) and the charge of the call. The calls must be listed in chronological order. Finally, print the total charge for the month in the format shown by the sample.

Sample Input:

10 10 10 10 10 10 20 20 20 15 15 15 15 15 15 15 20 30 20 15 15 10 10 10
10
CYLL 01:01:06:01 on-line
CYLL 01:28:16:05 off-line
CYJJ 01:01:07:00 off-line
CYLL 01:01:08:03 off-line
CYJJ 01:01:05:59 on-line
aaa 01:01:01:03 on-line
aaa 01:02:00:01 on-line
CYLL 01:28:15:41 on-line
aaa 01:05:02:24 on-line
aaa 01:04:23:59 off-line

Sample Output:

CYJJ 01
01:05:59 01:07:00 61 $12.10
Total amount: $12.10
CYLL 01
01:06:01 01:08:03 122 $24.40
28:15:41 28:16:05 24 $3.85
Total amount: $28.25
aaa 01
02:00:01 04:23:59 4318 $638.80
Total amount: $638.80

Ω

有一阵子没码题目了,感觉脑子和手都生锈了。用这道题来复健着实折磨。

极简翻译:首先给出每小时内通话的收费标准(美分/min)。然后给出同一月内不同用户的通话记录,通话记录的状态包括on-lineoff-line,然而对于一个用户而言两者也并非完全匹配,那么就需要找出每个用户所有匹配的通话记录对,最后按字母顺序依次输出本月内每个用户(按时间顺序)的所有匹配记录对,以及每一对相应的时长(min)与收费($),最后输出该用户在本月的总收费。

脑袋隐隐作痛,有几个棘手的地方:

  1. 同一个用户通话记录的匹配
  2. 一次通话的费用计算
  3. 用户名字和通话记录都要按顺序输出

首先定义了一个日期类,包含了时间的日时分,以及记录的状态和是否已匹配,同时重载了<,<<运算符,实现了换算成分钟的minutes()

class date
{
public:
    int d, h, m;
    bool isOnline, isPaired = false;

    inline bool operator<(const date &rhs) const { return this->minutes() < rhs.minutes(); }

    int minutes() const { return this->d * 1440 + this->h * 60 + this->m; }

    inline friend ostream &operator<<(ostream &os, const date &t)
    {
        printf("%02d:%02d:%02d", t.d, t.h, t.m);
        return os;
    }

    date(int _d = -1, int _h = -1, int _m = -1, bool flag = true) : d(_d), h(_h), m(_m), isOnline(flag) {};
};

这里我用set<date>容器来存储一个用户的通话记录,由于我重载了date的<,因此会自动按照时间先后进行存储,而用户与其通话记录集合则用map<string,set<date>>记录,map会自动按照名字顺序排序。

匹配的要求感觉题目说的不是很清楚,简单地说,只有同一个用户在相邻时间点(之间没有其他记录)的on-lineoff-line可以匹配成功,其余无法匹配的记录直接忽略。那么我在遍历集合的时候,遇到on-line就保留其时间,遇到off-line就检查保留的on-line记录是否已匹配,未匹配就计算相应费用,并标记匹配变量。

计算费用我是直接分类计算,on-lineoff-line的当天单独计算,中间的天数直接乘以通话一天的总费用(⚠️这样计算的话还需要单独考虑同一天内,以及同一天同一小时内的通话记录)。还有一种方法是先分别计算两个状态从00:00:00开始的费用,然后直接相减,就不需要考虑这么多了。事实上,这个思路适用所有涉及到时间的计算。


C☺DE

#include <iostream>
#include <vector>
#include <set>
#include <map>

using namespace std;
vector<int> toll(25);

class date
{
public:
    int d, h, m;
    bool isOnline, isPaired = false;

    inline bool operator<(const date &rhs) const { return this->minutes() < rhs.minutes(); }

    int minutes() const { return this->d * 1440 + this->h * 60 + this->m; }

    inline friend ostream &operator<<(ostream &os, const date &t)
    {
        printf("%02d:%02d:%02d", t.d, t.h, t.m);
        return os;
    }

    date(int _d = -1, int _h = -1, int _m = -1, bool flag = true) : d(_d), h(_h), m(_m), isOnline(flag) {};
};

float cost(const date &on, const date &off)
{ 
    if (on.d == off.d && on.h == off.h)
        return (off.m - on.m) * toll[on.h] / 100.0;
    float sum = (60 - on.m) * toll[on.h] + off.m * toll[off.h];
    if (on.d < off.d)
    {
        for (int i = on.h + 1; i < 24; ++i)
            sum += 60 * toll[i];
        for (int i = 0; i < off.h; ++i)
            sum += 60 * toll[i];
    }
    else
        for (int i = on.h + 1; i < off.h; ++i)
            sum += 60 * toll[i];
    for (int i = on.d + 1; i < off.d; ++i)
        sum += 60 * toll[24];

    return sum / 100.0;
}

int main()
{
    for (int i = 0; i < 24; ++i)
    {
        cin >> toll[i];
        toll[24] += toll[i];
    }
    int n, M, d, h, m;
    cin >> n;
    string name, flag;
    map<string, set<date>> record;
    for (int i = 0; i < n; ++i)
    {
        cin >> name;
        scanf("%d:%d:%d:%d", &M, &d, &h, &m);
        cin >> flag;
        record[name].emplace(d, h, m, (flag == "on-line") ? true : false);
    }

    for (auto &r: record)
    {
        name = r.first;
        float money = 0, sum = 0;
        date pre_online;
        for (auto &k: r.second)
        {
            if (k.isOnline)
                pre_online = k;
            else if (!pre_online.isPaired && pre_online.d != -1)
            {
                if (sum == 0)
                    printf("%s %02d\n", name.c_str(), M);
                money = cost(pre_online, k);
                pre_online.isPaired = true;
                cout << pre_online << " " << k << " " << (k.minutes() - pre_online.minutes());
                printf(" $%.2f\n", money);
                sum += money;
            }
        }
        if (sum != 0)
            printf("Total amount: $%.2f\n", sum);
    }
}

Σ Notes

  1. $1=100美分,/100.0!
  2. 如果一个用户一对匹配的通话记录都没有,那么就无需输出
  3. toll[24]存放的是通话一天的收费标准(美分/min)
  4. 测试点说明:0-Sample,1、2-不要输出没有费用的用户,3-含有同一天同一小时内的通话记录
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值