当前位置: 代码迷 >> 综合 >> pat 甲级 1016 phone bill
  详细解决方案

pat 甲级 1016 phone bill

热度:64   发布时间:2023-12-14 23:21:19.0

题目如下:

1016 Phone Bills (25 分)

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

照例,我先大概翻译一下这个题。这题大概意思是说先给你24个数字,表示一天之中从0:00-1:00开始的24个时间段的每分钟收费标准。然后给你一个int类型的数N,接下来会给你N行信息,分别是姓名,时间和状态。然后我们要根据这24个数字和N行信息,得到该用户每个通话记录的时长,费用以及该用户这个月的总费用。翻译大概就是这样,但其实这个题是存在一些坑的。

       1.若一个用户的名下没有合法有效的记录则不对这个用户进行输出。

       2.存在无效记录,需要忽略。

       3.通话记录的时间跨度可以很大,甚至可以跨过好几天,这一点要先考虑到。

解题的思路如下:

首先解决数据结构的问题,在这里我采用结构体数组,每个结构体包括用户姓名,时间(分别采用int和string储存)和状态。

int表示的时间是为从每个月第一天开始到该记录时间的秒数(其实可以用分钟数),这个时间主要用来排序。

结构体代码如下:

struct PhoneBill
{string name;string timeString;int timeInt;bool state;
};

       接着完成数据的输入和储存之后先要对这个数组进行排序,注意这里要进行两次排序,第一次按时间进行排序,第二次按名字进行排序,特别要注意的是第二次排序,这里需要的是稳定的排序,也就是stl中的stable_sort,函数的具体用法我这里就不赘述了。这里还需要写几个比较函数,分别是比较姓名和时间的,比较的函数代码如下:

bool compareName(PhoneBill a, PhoneBill b) //比较姓名
{return a.name < b.name;
}bool compareTime(PhoneBill a, PhoneBill b) //比较时间
{return a.timeInt<b.timeInt;
}

       接着就要进入正题了,按名字的顺序对N条信息进行遍历,此时,N条信息的姓名和时间已经按照我们想要的顺序排列,我们所要做的就是对信息的配对和筛选。对信息的遍历还需要一个辅助数组visited[],用来记录该记录是否访问过,若访问过则对该数组元素赋为true,若visited元素记录的为true,则表示已经访问过,以后不再访问。信息的配对和筛选也是该问题的难点,可以参考我的代码理解一下。

       还有一个难点则是对账单的计算,这个地方确实对我造成了一些困扰,在这里我大概阐述一下我的思路:对每个时间都计算从每个月第一天开始通话到该时间所需要的花费。而每一笔通话的账单可以由结束时间计算所得的花费减去开始时间计算所得的花费所得出。

计算的函数如下:

double getMoney(vector<int> TimeRate, string EarlyTime, string LaterTime)
{double wholeDay = 0;  //完整一天的总花费for (int i = 0; i < 24; i++){wholeDay += TimeRate[i] * 60;}double EarlyBill=0;  //开始时间的总花费double LaterBill=0;  //结束时间的总花费EarlyBill = (EarlyTime[3]-48) * 10 * wholeDay + (EarlyTime[4]-48) * wholeDay + getHourMoney(TimeRate, (EarlyTime[6] - 48) * 10+ (EarlyTime[7] - 48)) + TimeRate[(EarlyTime[6] - 48) * 10 + (EarlyTime[7] - 48)] * ((EarlyTime[9] - 48) * 10 + (EarlyTime[10] - 48));LaterBill = (LaterTime[3]-48) * 10 * wholeDay+ (LaterTime[4]-48) * wholeDay+ getHourMoney(TimeRate, (LaterTime[6] - 48) * 10 + (LaterTime[7] - 48))+ TimeRate[(LaterTime[6] - 48) * 10 + (LaterTime[7] - 48)] * ((LaterTime[9] - 48) * 10 + (LaterTime[10] - 48));return (LaterBill - EarlyBill)/100;  //两个时间花费的差值就是我们所需的每次通话的花费
}

这个函数还需要一个函数作为辅助,以使这个函数逻辑比较清楚,辅助函数用于计算每个时间的小时数所需的花费,代码如下:

double getHourMoney(vector<int> TimeRate, int h)
{double hourMoney = 0.00;for (int i = 0; i < h; i++){hourMoney += TimeRate[i] * 60;}return hourMoney;
}

至此,整个题目的思路以及大概明晰了,下面放上完整代码:

#include<iostream>
#include<string>
#include<iomanip>
#include<vector>
#include<algorithm>
using namespace std;
struct PhoneBill
{string name;string timeString;int timeInt;bool state;
};
bool compareName(PhoneBill a, PhoneBill b)
{return a.name < b.name;
}
bool compareTime(PhoneBill a, PhoneBill b)
{return a.timeInt<b.timeInt;
}
double getHourMoney(vector<int> TimeRate, int h)
{double hourMoney = 0.00;for (int i = 0; i < h; i++){hourMoney += TimeRate[i] * 60;}return hourMoney;
}
double getMoney(vector<int> TimeRate, string EarlyTime, string LaterTime)
{double wholeDay = 0;  //完整一天的总花费for (int i = 0; i < 24; i++){wholeDay += TimeRate[i] * 60;}double EarlyBill=0;  //开始时间的总花费double LaterBill=0;  //结束时间的总花费EarlyBill = (EarlyTime[3]-48) * 10 * wholeDay + (EarlyTime[4]-48) * wholeDay + getHourMoney(TimeRate, (EarlyTime[6] - 48) * 10+ (EarlyTime[7] - 48)) + TimeRate[(EarlyTime[6] - 48) * 10 + (EarlyTime[7] - 48)] * ((EarlyTime[9] - 48) * 10 + (EarlyTime[10] - 48));LaterBill = (LaterTime[3]-48) * 10 * wholeDay+ (LaterTime[4]-48) * wholeDay+ getHourMoney(TimeRate, (LaterTime[6] - 48) * 10 + (LaterTime[7] - 48))+ TimeRate[(LaterTime[6] - 48) * 10 + (LaterTime[7] - 48)] * ((LaterTime[9] - 48) * 10 + (LaterTime[10] - 48));return (LaterBill - EarlyBill)/100;  //两个时间花费的差值就是我们所需的每次通话的花费
}
int main()
{vector<int> TimeRate(24);for (int i = 0; i < 24; i++){cin >> TimeRate[i];}int N;cin >> N;vector<PhoneBill> list(N);for (int i = 0; i < N; i++){cin >> list[i].name;string time,state;cin >> time >>state;int tempTime = 0;tempTime = (time[3] - 48) * 10 * 24 * 3600 + (time[4] - 48) * 24 * 3600 + (time[6] - 48) * 10 * 3600 + (time[7] - 48) * 3600 + (time[9] - 48) * 10 * 60 + (time[10] - 48) * 60;list[i].timeString = time;list[i].timeInt = tempTime;if (state == "on-line"){list[i].state = true;  //true为online}else{list[i].state = false;  //false为offline}}sort(list.begin(), list.end(), compareTime);  //对时间排序stable_sort(list.begin(), list.end(), compareName);  //对姓名排序vector<bool> visited(N);for (int i = 0; i < N; i++)  {if (visited[i] == false){int count = 0;  //用于记录合法配对的次数bool state =false;  //用于对配对状态的记录string time;        //用于对通话开始时间的记录double moneySum = 0; //一个人的总账单for (int j = i; j < N; j++){	if (list[j].name == list[i].name)  {double moneyOneBill = 0;  //一通电话的账单visited[j] = true;if (list[j].state == true && state == false){state = true;time = list[j].timeString;}else if (list[j].state == false && state == true)  //只有这种情况才是合法配对{if (count == 0){cout << list[i].name << " " << list[i].timeString.substr(0, 2) << endl;}count++;state = false;cout << time.substr(3,8) << " " << list[j].timeString.substr(3,8) << " ";int minutes = 0;minutes = (list[j].timeString[3] - 48) * 10 * 24 * 60  //计算题目所需的通话分钟数+ (list[j].timeString[4] - 48) * 24 * 60 + (list[j].timeString[6] - 48) * 10 * 60 + (list[j].timeString[7] - 48) * 60 + (list[j].timeString[9] - 48) * 10 + (list[j].timeString[10] - 48) * 1;minutes = minutes - ((time[3] - 48) * 10 * 24 * 60 + (time[4] - 48) * 24 * 60 + (time[6] - 48) * 10 * 60 + (time[7] - 48) * 60 + (time[9] - 48) * 10 + (time[10] - 48) * 1);cout << minutes<<" ";moneyOneBill = getMoney(TimeRate, time, list[j].timeString);moneySum += moneyOneBill;cout << "$" << setiosflags(ios::fixed) << setprecision(2) << moneyOneBill<< endl;}else if (list[j].state == true && state == true){state = true;time = list[j].timeString;}else if (list[j].state == false && state == false){state = false;//time = list[i].state;}}}if (count>0){cout << "Total amount: $" << setiosflags(ios::fixed) << setprecision(2) << moneySum << endl;}}}
}

有什么不明白的可以在下面评论,我看到应该都会回复的。

  相关解决方案