题目如下:

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

这道题要求对一个月内多个人的通话记录进行统计,对每个有通话的日期进行统计计算得到话费,并且按照格式输出。

题目的难度主要表现在存储结构的选定、无用数据的排除、输出顺序三个方面。

我最初想到的办法是采用容器分别存储名字和记录,然后分别对对应的记录处理,名字排序,遇到了许多问题。

后来参考了sunbaigui的解决方法,他将名字和记录一起存储在vector中,然后用sort函数对vector排序,排序规则为优先按照字典顺序排列名字,如果名字相同则按照时间顺序(通过对时、分、秒加和来衡量)排列,这样排列完毕后的记录是按照名称从小到大,时间从前到后的顺序,对于统计是十分方便的。

sunbaigui的博客中提到的排除无用记录的方法非常巧妙,由于排完序的具有时间从前到后的顺序,并且一个人的记录是连续分布的,因此只需要从前到后的先找on,再找off,创建一个新的vector,在没有on的情况下遇到on直接压入,如果在有on的情况下碰到on则先弹出上一条无效的on,再把这个on压入;如果on之后碰到了off,并且名字一致(说明还是这个人的记录),则把off压入。这里有个问题,如果最后一条是on,则这个无效记录是无法被排除的(没有机会遇到下一个on来弹出它),因此应该在前面的基础上判断vector中的最后一个元素是否是on,是on则直接弹出,否则说明是有效记录。

接下来只需要对这个新vector(全部是有效的、有序记录)遍历输出即可,从第一个元素开始,每两个相邻元素必定构成一个通话记录,输出比较繁琐,需要谨慎处理。

关于日期的计算,要考虑全面,比如电话跨天,因此在考虑时间的时候应该把天、小时、分钟全部加起来,计算为分钟之和,既方便了排序,在计算价格的时候也可以方便的处理,计算价格采用的方法是以月初为基准,分别计算一条通话记录中off和on的话费然后做差。

下面的算法是在sunbaigui博客上直接摘录的,我在理解的基础上加了些注释便于理解,在这里感谢sunbaigui提供的众多优良解法。

#include<iostream>
using namespace std;
#include<vector>
#include<string>
#include<algorithm>
#include<stdio.h> struct Call
{
string name;
int month;
int date;
int hour;
int minute;
int total; // 总时间是对date、hour、minute之和换算为分钟,便于排序和时间的运算。
string status;
}; int charge[24];
vector<Call> all_calls; // 输入的原始记录
vector<Call> format_calls; // 对输入记录处理之后 bool compare(Call a,Call b) // 对sort函数指定比较规则,首先是名字按照字典顺序排序,如果名字相同则按时间顺序
{
if(a.name < b.name)
return 1;
else if(a.name == b.name && a.total < b.total)
return 1;
else
return 0;
} //calculate money from the begin of month to the time given
int chargeByTime(int time) // 对给定的分钟数相对于月初计算费用,off和on的费用差即为一条通话记录的话费。
{
int hours = time/60;
int minutes = time%60;
int money = 0;
int i;
for(i = 0;i<hours;i++)
money += charge[i%24]*60;
money += charge[i%24]*minutes;
return money;
} double calCost(Call s,Call t) // 计算话费的方法为off相对月初的话费减去on相对月初的话费
{
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.minute-s.minute);
} int main()
{
for(int i = 0;i<24;i++)
cin>>charge[i];
int N;
cin>>N;
while(N--)
{
Call c;
cin>>c.name;
cin>>c.month;
getchar(); // 注意getchar printf等是在头文件stdio.h中声明的。
cin>>c.date;
getchar();
cin>>c.hour;
getchar();
cin>>c.minute;
c.total = c.minute + 60*c.hour + 24*60*c.date;
cin>>c.status;
all_calls.push_back(c);
}
sort(all_calls.begin(),all_calls.end(),compare); // sort函数在algorithm.h中声明 // filter delete those bad record 过滤无用的通话记录
bool haveonline = false; // 用于判断是否上一条是on,从而判断应该丢弃上一条还是保留。
string curname; // 用于存储上一条记录的名字,如果这一条是off,并且名字和上一条一致,才能构成一条通话记录
for(int i=0;i<all_calls.size();i++)
{
if(haveonline == false && all_calls[i].status =="on-line" ) // 第一次遇到on,直接压入
{
format_calls.push_back(all_calls[i]);
haveonline = true;
curname = all_calls[i].name;
}
else if(haveonline == true && all_calls[i].status =="on-line") // 第二次遇到on,说明上一个on是无效的,先弹出上一条,再压入这一条。
{
format_calls.pop_back();
format_calls.push_back(all_calls[i]);
haveonline = true;
curname = all_calls[i].name;
}
else if(haveonline == true && all_calls[i].status =="off-line"&&all_calls[i].name ==curname) // 匹配成功的通话记录,压入off。
{
format_calls.push_back(all_calls[i]);
haveonline = false;
}
}
//the last must be offline
if((*(format_calls.end()-1)).status == "on-line") // 上面无法处理最后一条为on的情况,因此检测最后一条是否是on,是直接丢弃。
format_calls.pop_back(); //output
double totalcost = 0; // 用于累加总话费
curname = ""; // 用于判断是否应该输出总话费(总话费在一个人输出完毕后输出,第一次不输出,用curname是否为空来区分)
for(int i=0;i<format_calls.size();i+=2)
{ if(format_calls[i].name != curname)
{
if(curname!="")
{
printf("Total amount: $%.2f\n",totalcost);
totalcost = 0;
printf("%s %02d\n",format_calls[i].name.c_str(),format_calls[i].month);
}
else
{
printf("%s %02d\n",format_calls[i].name.c_str(),format_calls[i].month);
}
curname = format_calls[i].name;
}
printf("%02d:%02d:%02d",format_calls[i].date,format_calls[i].hour,format_calls[i].minute);
printf(" ");
printf("%02d:%02d:%02d",format_calls[i+1].date,format_calls[i+1].hour,format_calls[i+1].minute);
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); }

1016. Phone Bills (25) -vector排序(sort函数)的更多相关文章

  1. PAT 甲级 1016 Phone Bills (25 分) (结构体排序,模拟题,巧妙算时间,坑点太多,debug了好久)

    1016 Phone Bills (25 分)   A long-distance telephone company charges its customers by the following r ...

  2. 1016. Phone Bills (25)——PAT (Advanced Level) Practise

    题目信息: 1016. Phone Bills (25) 时间限制 400 ms 内存限制 32000 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A l ...

  3. C++对一组pair数据进行排序(sort函数的使用)

    最近在写一个算法的时候,把一些数据存在了pair中,并且需要根据pair中first或者second的值对这些数据进行排序.比如:输入数据(1,2).(4,2).(3,3).(2,1)根据first的 ...

  4. 排序 sort函数

    sort函数见下表: 函数名 功能描述 sort 对给定区间所有元素进行排序 stable_sort 对给定区间所有元素进行稳定排序 partial_sort 对给定区间所有元素部分排序 partia ...

  5. PAT甲题题解-1016. Phone Bills (25)-模拟、排序

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6789229.html特别不喜欢那些随便转载别人的原创文章又不给 ...

  6. 【PAT甲级】1016 Phone Bills (25 分)(结构体排序)

    题意: 输入24个正整数代表从0到23每个小时通话一分钟花费的美分.输入一个正整数N(<=1000),然后输入N组字符串,每个字符串包含客户的名字和通话的时刻以及打出或者挂断的状态. 按照字典序 ...

  7. PAT A 1016. Phone Bills (25)【模拟】

    题目:https://www.patest.cn/contests/pat-a-practise/1016 思路:用结构体存储,按照名字和日期排序,然后先判断是否有效,然后输出,时间加减直接暴力即可 ...

  8. 1016 Phone Bills (25)(25 point(s))

    problem A long-distance telephone company charges its customers by the following rules: Making a lon ...

  9. 1016 Phone Bills (25分)

    复建的第一题 理解题意 读懂题目就是一个活,所以我们用观察输出法,可以看出来月份,以及时间和费用之间的关系. 定义过程 然后时间要用什么来记录呢?day hour minute 好麻烦呀..用字符串吧 ...

随机推荐

  1. java底层学习

    额,马上就要面试了,Java的底层肯定是需要了解的.网上找了找java的底层文章,做个记号.java底层主要是类的加载.连接和初始化. 本文主要分为四个方面: (1)java底层概述 (2)new和n ...

  2. java后台通过Servlet给用户发送手机短信验证码,第一次写勿喷,欢迎转载

    短信验证码跟自己在Servlet画的验证码不一样,我们不用管短信验证码是怎么产生的,我们只需要关注如何调用短信验证码,在短信验证码里面添加 自己需要的随机数或者其他的内容. 现在直接上流程 第一步找一 ...

  3. 多表insert操作详解

    --1.无条件的多表insert all ; ; ; --没有条件,向多个目标表全量插入,必须有all insert all --不指定emp_1后面的列,也不指定values,那么emp_1中的所有 ...

  4. 浅析JS异步执行机制

    前言 JS异步执行机制具有非常重要的地位,尤其体现在回调函数和事件等方面.本文将针对JS异步执行机制进行一个简单的分析. 从一份代码讲起 下面是两个经典的JS定时执行函数,这两个函数的区别相信对JS有 ...

  5. Java中的内存分配

    Java程序在运行时,需要在内存中分配空间,为了提高效率,就对空间进行了不同区域的划分,因为每一片区域否有特定的处理数据方式和内存管理方式. 1.栈存储局部变量 2.堆存储new出来的东西 3.方法区 ...

  6. Python3 字典

    字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中 ,格式如下所示: d = ...

  7. MySQL注释中的sql也可能执行

    MySql支持三种注释形式:# 和–属于单行注释,注释范围为该行的结尾:/* */注释属于多行注释,此外该种注释还可以实现行内注释.具体的使用情况如下图中所示(四种使用情形): 除此之外,/* */这 ...

  8. Android自定义View(LimitScrollerView-仿天猫广告栏上下滚动效果)

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/53303872 本文出自:[openXu的博客] 1分析 2定义组合控件布局 3继承最外层控件 ...

  9. Android底层开发经验

    最近看到一个博客,他的博文虽然是转载的,但源作者肯定对底层的理解可谓是非常透彻,一副思维导图就可以将整个重要体系建立起来,非常适合大家学习.学习不单单只要有代码,生动有趣更重要.在此推荐一波: htt ...

  10. The packages can be overrided by Java Endorsed Standards

     Endorsed Standards APIs The Endorsed Standards for Java SE constitute all classes and interfaces ...