1016. Phone Bills (25)

题目链接:http://www.patest.cn/contests/pat-a-practise/1016

题目:



时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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

分析:

根据电话记录计算各个用户的费用,其中每个小时的费用都不相同,用户的记录要成对才有效,即一个online对应于一个offline,而且必须是最近的online和offline(A online; A online; A offline; A offline的话则按第二个online和第一个offline计算中间的费用,而第一个online和第2个offline记录作废)

注意点:

(1)如何把记录整理,这里就先需要一个比较函数,先按姓名排序,再按其时间排序,并且有一个总体记录和有效记录,所以要有两个vector,不然删除太麻烦了。

(2)把无效的记录删除,对于每一个用户,要找到其有效的online-offline对,也是比较难的,里面的逻辑要理清楚:要记录一个是否有上线记录的标记haveonline,要记录当前用户的名字curname。具体见代码及注释。

(3)费用的计算:因为各个小时区间内的费用都不相同,所以不能简单的通过计算时间差来解决,这里有个小技巧是对于时间段s-t的费用计算,设定一个起始时间零点t0,都计算t0到ti的费用综合costi,然后把cost进行相减即可。

案例分析:

先读入每个小时的费用

针对记录:

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

先排序,得到:

CYJJ 01:01:05:59 on-line
CYJJ 01:01:07:00 off-line

CYLL 01:01:06:01 on-line
CYLL 01:01:08:03 off-line
CYLL 01:28:15:41 on-line
CYLL 01:28:16:05 off-line

aaa 01:01:01:03 on-line
aaa 01:02:00:01 on-line
aaa 01:04:23:59 off-line
aaa 01:05:02:24 on-line
再筛选出有效记录,即成对的on-line和off-line对

CYJJ 01:01:05:59 on-line
CYJJ 01:01:07:00 off-line

CYLL 01:01:06:01 on-line
CYLL 01:01:08:03 off-line
CYLL 01:28:15:41 on-line
CYLL 01:28:16:05 off-line

aaa 01:02:00:01 on-line
aaa 01:04:23:59 off-line
统计各用户费用:


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



AC代码:

(这里我参考了王道上的代码,并加上了详细的注释)

#include<stdio.h>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
struct Call{
 char name[21];
 int month;
 int date;
 int hour;
 int min;
 int total;
 bool operator < (const Call &C)const{
  int tmp = strcmp(name, C.name);
  if (tmp != 0)return tmp < 0;
  else return total < C.total;
 }//比较函数,按照姓名先后,时间小大的顺序排序
 char status[10];
};//电话记录结构体
int charge[24];//存放每小时的电话费用
vector<Call> all_calls;//所有的电话记录
vector<Call> format_calls;//整理后的电话记录
int chargeByTime(int time){//计算t0初始时间到指定时间time的总费用
 int hours = time / 60;
 int min = time % 60;
 int money = 0;
 int i;
 for (i = 0; i < hours; i++){
  money += charge[i % 24] * 60;
 }
 money += charge[i % 24] * min;
 return money;
}
double calCost(Call s, Call t){
//这里有个技巧,当要算s到t时间的电话费用时,都从t0时间开始算起,这样的话就会开始都是整小时数,方便计算和函数编写
 return (double)(chargeByTime(t.total) - chargeByTime(s.total)) / 100;
}
int calLast(Call s, Call t){
 return (t.date - s.date) * 24 * 60 + (t.hour - s.hour) * 60 + (t.min - s.min);
}//计算通话持续时间
int main(void){
 //freopen("F://Temp/input.txt","r",stdin);
 for (int i = 0; i < 24; i++){
  scanf("%d", &charge[i]);
 }//读入各小时区间通话费用
 int k;
 scanf("%d", &k);
 while (k--){
  Call c_tmp;
  scanf("%s%d:%d:%d:%d%s", c_tmp.name, &c_tmp.month, &c_tmp.date, &c_tmp.hour, &c_tmp.min, c_tmp.status);
  c_tmp.total = c_tmp.date * 24 * 60 + c_tmp.hour * 60 + c_tmp.min;
  all_calls.push_back(c_tmp);
 }//读入通话记录并转化当前通话的时刻
 sort(all_calls.begin(), all_calls.end());//先排序,按照姓名,再按照时间排序
 bool haveonline = false;
 char curname[21];//当前用户
 char online[10] = "on-line";
 char offline[10] = "off-line";
//------------------------整理的过程,很关键--------------
 for (int i = 0; i < all_calls.size(); i++){
  if (haveonline == false && strcmp(all_calls[i].status, online) == 0){//如果用户没有上线,并且当前记录为上线的话
   format_calls.push_back(all_calls[i]);//把当前记录放入format_calls
   haveonline = true;//并置haveonline为已上线
   strcpy(curname, all_calls[i].name);//并记录当前用户的名字
  }
  else if (haveonline == true && strcmp(all_calls[i].status, online) == 0){//如果用户已经上线,并且当前记录为上线的话,则按后者的计算,这是为了应对A用户上线,再接着是B用户上线,前者A上线记录作废;或是两次都是A用户上线,以后者计算
   format_calls.pop_back();
   format_calls.push_back(all_calls[i]);//需要先把之前上线的记录拿掉,放入更新后的
   haveonline = true;
   strcpy(curname, all_calls[i].name);//名字也要为更新后的
  }
  else if (haveonline == true && strcmp(all_calls[i].status, offline) == 0 && strcmp(curname, all_calls[i].name) == 0){//如果用户已上线,并且当前记录是下线,说明是一个电话记录完成
   format_calls.push_back(all_calls[i]);//把下线记录放入format_calls
   haveonline = false;//并把haveonline置为非上线
  }
 }
 if (strcmp((*(format_calls.end() - 1)).status, online) == 0){//如果碰到下线记录,当时用户名不匹配,比如遇到A上线,B下线的记录,则说明A的记录不完整,需要把A上线的记录从format_calls中删去
  format_calls.pop_back();
 }
 double totalcost = 0;
 char kong[21] = "";
 strcpy(curname, kong);
//------------------------格式化输出,也很重要-----------------
 for (int i = 0; i < format_calls.size(); i += 2){
  if (strcmp(format_calls[i].name, curname) != 0){
   if (strcmp(curname, kong) != 0){//碰到了非第一个用户的新用户
    printf("Total amount: $%.2f\n", totalcost);//输出前一个用户的总费用
    totalcost = 0;//并把totalcost重新置为0
    printf("%s %02d\n", format_calls[i].name, format_calls[i].month);//输出新用户的头部信息
   }
   else//curname=="",也就是是第一个用户,所以不用输出上一个用户的totalcost
   {
    printf("%s %02d\n", format_calls[i].name, format_calls[i].month);
   }
   strcpy(curname, format_calls[i].name);//把新用户的名称记录
  }
  printf("%02d:%02d:%02d", format_calls[i].date, format_calls[i].hour, format_calls[i].min);
  printf(" ");
  printf("%02d:%02d:%02d", format_calls[i + 1].date, format_calls[i + 1].hour, format_calls[i + 1].min);
  printf(" ");
  printf("%d", calLast(format_calls[i], format_calls[i + 1]));//输出当前记录持续时间
  printf(" ");
  printf("$%.2f\n", calCost(format_calls[i], format_calls[i + 1]));//输出当前记录费用
  totalcost += calCost(format_calls[i], format_calls[i + 1]);//累计到总费用中
 }
 printf("Total amount: $%.2f\n", totalcost);
}


——Apie陈小旭


时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值