1016. Phone Bills (25) -vector排序(sort函数)
题目如下:
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函数)的更多相关文章
- PAT 甲级 1016 Phone Bills (25 分) (结构体排序,模拟题,巧妙算时间,坑点太多,debug了好久)
1016 Phone Bills (25 分) A long-distance telephone company charges its customers by the following r ...
- 1016. Phone Bills (25)——PAT (Advanced Level) Practise
题目信息: 1016. Phone Bills (25) 时间限制 400 ms 内存限制 32000 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A l ...
- C++对一组pair数据进行排序(sort函数的使用)
最近在写一个算法的时候,把一些数据存在了pair中,并且需要根据pair中first或者second的值对这些数据进行排序.比如:输入数据(1,2).(4,2).(3,3).(2,1)根据first的 ...
- 排序 sort函数
sort函数见下表: 函数名 功能描述 sort 对给定区间所有元素进行排序 stable_sort 对给定区间所有元素进行稳定排序 partial_sort 对给定区间所有元素部分排序 partia ...
- PAT甲题题解-1016. Phone Bills (25)-模拟、排序
博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6789229.html特别不喜欢那些随便转载别人的原创文章又不给 ...
- 【PAT甲级】1016 Phone Bills (25 分)(结构体排序)
题意: 输入24个正整数代表从0到23每个小时通话一分钟花费的美分.输入一个正整数N(<=1000),然后输入N组字符串,每个字符串包含客户的名字和通话的时刻以及打出或者挂断的状态. 按照字典序 ...
- PAT A 1016. Phone Bills (25)【模拟】
题目:https://www.patest.cn/contests/pat-a-practise/1016 思路:用结构体存储,按照名字和日期排序,然后先判断是否有效,然后输出,时间加减直接暴力即可 ...
- 1016 Phone Bills (25)(25 point(s))
problem A long-distance telephone company charges its customers by the following rules: Making a lon ...
- 1016 Phone Bills (25分)
复建的第一题 理解题意 读懂题目就是一个活,所以我们用观察输出法,可以看出来月份,以及时间和费用之间的关系. 定义过程 然后时间要用什么来记录呢?day hour minute 好麻烦呀..用字符串吧 ...
随机推荐
- 阿里云部署Node.js项目(CentOS)
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,用来方便地搭建快速的易于扩展的网络应用.Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又 ...
- dnc开源梦之队2018 开源项目精选集
dnc开源梦之队2018 dnc开源项目选择标准 dnc = .NET Core.dotnet core 1.支持dnc 2.x,Github star数量100以上,最近2月活跃更新 2.轻量级.示 ...
- python类(class)中参数self的解释说明
python类(class)中参数self的简单解释 1.self只有在类的方法中才会有,其他函数或方法是不必带self的. 2.在调用时不必传入相应的参数.3.在类的方法中(如__init__),第 ...
- JavaScript switch 语句
switch 语句用于基于不同的条件来执行不同的动作. JavaScript switch 语句 请使用 switch 语句来选择要执行的多个代码块之一.你可以在JavaScript编程实战中了解怎么 ...
- Unity3D各平台Application.xxxPath的路径
前几天我们游戏在一个同事的Android手机上启动时无法正常进入,经查发现Application.temporaryCachePath和Application.persistentDataPath返回 ...
- Android开发学习之路--基于vitamio的视频播放器(二)
终于把该忙的事情都忙得差不多了,接下来又可以开始good good study,day day up了.在Android开发学习之路–基于vitamio的视频播放器(一)中,主要讲了播放器的界面的 ...
- Java安全套接字扩展——JSSE
上节已经介绍了SSL/TLS协议的通信模式,而对于这些底层协议,如果要每个开发者都自己去实现显然会带来不必要的麻烦,正是为了解决这个问题Java为广大开发者提供了Java安全套接字扩展--JSSE,它 ...
- Ubuntu 16.04 安装和使用QQ最简洁的方式
推荐参考网址: 1 http://www.ubuntukylin.com/ 2 http://www.ubuntukylin.com/application/ Wine QQ 1 http:// ...
- linux中Cron定时任务系统命令详解
分类:Linux VPS教程 作者:阿川 发布时间:October 13, 2011 有很多同学在购买VPS之后,需要用到计划任务.但是又对计划任务不太了解,所以.今天我们的帮助中心主要是给大家提供一 ...
- Dynamics CRM 后台通过组织服务获取时间字段值的准确转换
做CRM开发的都知道,在系统时间字段的处理上是有讲究的,因为数据库中存的是UTC时间,CRM的界面时间字段会根据个人设置中的时区以及格式自动调整,这是最基本的一面,那还有很多使用时间的场景,比如脚本使 ...