顽强的小白
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
题目解析
这是一道对我来说比较复杂的排序题了,最后还是按参考书上写的。
题目大意是输出电话账单,电话费每个小时的单价各有不同,给出几条电话记录,有姓名,开始时间,电话状态(挂断还是接听),找出有效的电话记录,输出单个通话记录的时间,价钱,最后输出这个人的所有记录总价。
思路:
第一步要理解何为有效的电话记录,题目要求为接听和挂断之间没有其他记录就为有效记录,也就是需要on和off是挨着的,如果需要输出就必须先判断有没有有效记录,这里就很有趣了,只要判断在同一个人的通话记录中按照时间顺序on后面有off就行,此处无须深究这记录是否连续,因为按照参考书的思路,判断是否需要输出和寻找有效记录是分开的。
- 判断是否需要输出的同时也定位了相同名字的片段起始,也就是on到next之间的记录。
- 忘了说排序的问题,因为给出的数据都是一个月的所以记录时间的时候我没有计算月的,而是按照dd2460+hh*60+m的公式计算,用得到的时间来从小到大排序。
- 判断需要输出后,就在on到next的片段中寻找有效记录,也就是需要找到on和off紧挨着的片段
- 然后就是处理这个有效片段了,要计算时间也要计算价格,这个方法我学了两遍还是老是想不到,希望这次印象能深一点,简单来说就是一分一分加上去,直到加到相等为止,加多少次就是多长时间,这个价钱也是这么一分一分加,也方便。
- 余下是输出问题,问题不大。
代码实现
我写的有些地方欠思考,偷懒了许多。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=1005;struct customer{
char name[22];
int month,dd,hh,m;
int time;
int tag;
}cus[maxn],temp;
int price[24];
void deal(int a,int b,int &time,int &money){
temp=cus[a];
time=0;
money=0;
while(temp.dd<cus[b].dd||temp.hh<cus[b].hh||temp.m<cus[b].m){
time++;
temp.m++;
money+=price[temp.hh];
if(temp.m>=60){
temp.m=0;
temp.hh++;
}
if(temp.hh>=24){
temp.dd++;
temp.hh=0;
}
}}
bool cmp(customer a,customer b){
if(strcmp(a.name,b.name)==0){
return a.time <b.time;
}else
return strcmp(a.name,b.name)<0;
}
int main(){ int n,mm,dd,hh,m;
char tag[10];
for(int i=0;i<24;++i){
scanf("%d",&price[i]);
}
scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%s %d:%d:%d:%d %s",cus[i].name,&mm,&dd,&hh,&m,tag);
if(strcmp(tag,"on-line")==0){
cus[i].tag=1;
}else{
cus[i].tag=0;
}
cus[i].month=mm;
cus[i].time=dd*24*60+hh*60+m;
cus[i].dd=dd;
cus[i].hh=hh;
cus[i].m=m;
}
sort(cus,cus+n,cmp);
char name[22];
int on=0,off,next;
while(on<n){
int needPrint=0;
next=on;
while(next<n&&strcmp(cus[on].name,cus[next].name)==0){ //在姓名相同的记录片段中,判断需不需要输出
if(cus[next].tag==1&&needPrint==0){
needPrint=1;
}else if(needPrint==1&&cus[next].tag==0){ //这里很有趣,如果在on后找到off就一定有配对的现象
//都不需要考虑是否连续
needPrint=2;
}
next++;
}
if(needPrint<2){ //没有找到配对的,不需要后面的输出步骤
on=next;
continue;
}
int totalMoney=0;
printf("%s %02d\n",cus[on].name,cus[on].month);
while(on<next){ //开始寻找匹配的连续记录并且输出
while(on<next-1&&
!(cus[on].tag==1&&cus[on+1].tag==0) ){
++on;
}
off=on+1;
if(off==next){
on=next;
break;
}
printf("%02d:%02d:%02d ",cus[on].dd,cus[on].hh,cus[on].m);
printf("%02d:%02d:%02d ",cus[off].dd,cus[off].hh,cus[off].m);
int time,money;
deal(on,off,time,money);
totalMoney+=money;
printf("%d $%.2f\n",time,money/100.0);
on=off+1;
}
printf("Total amount: $%.2f\n",totalMoney/100.0);
}
return 0;
}