题目如下:

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. Angular5学习笔记 http请求

    在anular4更新到angular5后,有些模块也发生了有些变化,例如http模块. 首先在app.module.ts里面引入HttpClientModule import { HttpClient ...

  2. python socket网络编程之粘包问题详解

    一,粘包问题详情 1,只有TCP有粘包现象,UDP永远不会粘包 你的程序实际上无权直接操作网卡的,你操作网卡都是通过操作系统给用户程序暴露出来的接口,那每次你的程序要给远程发数据时,其实是先把数据从用 ...

  3. ACM 继续畅通工程

    Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).现得到城镇道路统计 ...

  4. Docker Kubernetes 项目

    Kubernetes 是 Google 团队发起并维护的基于Docker的开源容器集群管理系统,它不仅支持常见的云平台,而且支持内部数据中心. 建于Docker之上的Kubernetes可以构建一个容 ...

  5. freemarker的使用

    一:freemarker是什么? freemarker是一个模板引擎,基于定义的模板和数据生成对应的文本(HTML,xml,java等),是一个生成文本的工具. 二:freemarker的使用方法 ( ...

  6. linux和android开发链接

    1.Tracy Mcgrady的专栏冰山一角:linux和Android底层开发,主要是mtk系列点击打开链接 2.郁闷Wednesday:嵌入式linux 单片机 android,点击打开链接 3. ...

  7. 剑指Offer——求职必备神器

    剑指Offer--求职必备神器 前言   不管是公司网申.银行招聘.面试等等,"谈谈你的职业规划"."以往工作中遇到了哪些棘手问题?你是如何解决的?".&quo ...

  8. 阻塞IO服务器模型之单线程服务器模型

    单线程服务器模型是最简单的一个服务器模型,几乎我们所有程序员在刚开始接触网络编程(不管是B/S结构还是C/S结构)都是从这个简单的模型开始.这种模型只提供同时一个客户端访问,多个客户端访问必须要等到前 ...

  9. java类加载器——ClassLoader

    Java的设计初衷是主要面向嵌入式领域,对于自定义的一些类,考虑使用依需求加载原则,即在程序使用到时才加载类,节省内存消耗,这时即可通过类加载器来动态加载. 如果你平时只是做web开发,那应该很少会跟 ...

  10. 【NPR】非真实感渲染实验室

    写在前面 前几天在知乎看到一个问题--关于非实感图形学或者风格化渲染有哪些好的书或者paper,我刚好接触过一些就去里面回答了一下.答完以后突然想在Unity里搞一个这样的集锦,把一些简单的NPR论文 ...