PAT甲级 1016 Phone Bills

题目原文

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.

中文翻译

第一行输入24个数分别为24个小时每分钟花费价格,第二行输入数N为数据个数,接下来N行按姓名,时间,状态依次输入。要求对于每个用户每次通话花费金额以及总金额进行统计,输入按字母表顺序排序。

解题思路

将此题分为三个部分解:

1.对于给定数据进行先按照姓名进行排序,再按照时间进行排序。

2.排序后将每个用户的状态进行一一对应。

3.将字符串形式的时间转化为数字类型计算花费总金额和花费时间。

首先创建结构体,保存每个用户每次通话的数据。对于第一个问题,使用sort函数进行直接排序。对于第二个问题,考虑到on状态时若有多个on则一定取最后一个on,off状态时若有多个off则一定取第一个off,故只要找状态为on且下一个数据状态为off且姓名相同的即可。对于第三个问题,先根据格式将起始时间和结束时间字符串转为为对应时间,再将对应时间化为和月初相差的分钟数,一个小时一个小时进行循环直至起始时间和结束时间相等即可。

特别注意:此题中不进行花费的用户数据不输出!如果不花费的用户也输出的话,测试点1和2通过不了。

#include <iostream>
#include<string>
#include<algorithm>

using namespace std;

struct Record{
    string name;
    string time;
    string state;
};


bool cmp(Record a, Record b)
{
    //首先按照姓名排序
    if (a.name != b.name)
        return a.name.compare(b.name)<0;
    //如果姓名相同,计算时间,按时间排序
    int tmp =a.time.compare(b.time);
    if (tmp != 0)
        return tmp < 0;
    //如果时间也一样的话,将on状态放在off状态前
    else
        return a.state > b.state;
}

void sortrecord(Record record[],int num){
    sort(record,record+num,cmp);
}

float timetrans(string starttime,string endtime,int cost[]){
    //字符串数据转化为对于日期、小时、分钟
    int startday = (starttime[0]-'0')*10+(starttime[1]-'0'),endday = (endtime[0]-'0')*10+(endtime[1]-'0');
    int starthour = (starttime[3]-'0')*10+(starttime[4]-'0'),endhour = (endtime[3]-'0')*10+(endtime[4]-'0');
    int  startminute = (starttime[6]-'0')*10+(starttime[7]-'0'),endminute = (endtime[6]-'0')*10+(endtime[7]-'0');
    //花费总时间和总金额赋初值0
    int time = 0,price = 0;
    
    //如果在同天同小时,只要计算相差分钟数
    if (startday == endday && starthour == endhour){
        time = endminute - startminute;
        price = time * cost[starthour];
    }
    else{
        //将起始时间补整
        time += 60 - startminute;
        price += cost[starthour] * time;
        starthour = (starthour + 1) % 24;
        startminute = 0;
        if (starthour == 0){
            startday++;
        }
        int i = starthour;
        //将起始时间和结束时间都化作当月到现在经历的总分钟数
        int starttime = 1440*(startday-1) + 60*starthour + startminute,endtime = 1440*(endday-1) + 60*endhour + endminute;
        //一个小时一个小时遍历,直到相差时间不足一小时
        while (starttime + 60 <= endtime){
            time += 60;
            price += cost[i]*60;
            starttime += 60;
            i = (i + 1) % 24;
        }
        //添加最后的不足一小时的时间
        time += endtime - starttime;
        price += cost[i] * (endtime - starttime);
    }
    //美分转化美元
    float dollar = price/100.0;
    printf(" %d $%.2f\n",time,dollar);
    return dollar;
}

void output(Record record[],int num,int cost[]){
    //总金额赋初值0
    float totalamout = 0;
    //是否结束一个用户的遍历
    int flag = 1;
    //开始循环
    for (int i=0; i<num-1; i++){
        //是否进行到下一个用户
        if (i != 0){
            if (record[i].name != record[i-1].name){
                //若是,则结束此用户的遍历,输出总金额
                if (flag == 0){
                    printf("Total amount: $%.2f\n",totalamout);
                }
                //重新赋初值
                totalamout = 0;
                flag = 1;
            }
        }
        
        //如果状态为on且和下一个数据状态不同,姓名相同,则找到一对数据
        if (record[i].state == "on-line" && record[i+1].state != record[i].state && record[i+1].name == record[i].name){
            //若结束上一个用户遍历,输出此用户的姓名,开始此用户的遍历
            if (flag == 1){
                cout<<record[i].name<<" "<<record[i].time[0]<<record[i].time[1]<<endl;
                flag = 0;
            }
            //找到一对数据
            int j=i+1;
            string starttime = record[i].time.substr(3,8);
            string endtime = record[j].time.substr(3,8);
            cout<<starttime<<" "<<endtime;
            //将字符串数据转化为数字输出,并将金额加到总金额上
            totalamout += timetrans(starttime,endtime,cost);
        }
    }
    if (flag == 0){
        printf("Total amount: $%.2f\n",totalamout);
    }
}

int main(){
    int cost[24];
    for (int i=0; i<24; i++){
        cin>>cost[i];
    }
    int num;
    cin>>num;
    Record record[num];
    for (int i=0; i<num; i++){
        cin>>record[i].name>>record[i].time>>record[i].state;
    }
    //排序
    sortrecord(record,num);
    //输出
    output(record,num,cost);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值