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 好麻烦呀..用字符串吧 ...
随机推荐
- 数据结构之堆Heap
1. 概述 堆(也叫优先队列),是一棵完全二叉树,它的特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆).它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等. 2. 堆 ...
- python常用执行方式&变量&input函数
linux系统中执行py文件方式: ./a.py 需要执行权限 chmod -R 777(最大权限) 常用执行方式: 1. ./a.py2. python a.py 文件内部头加上 #!/usr/b ...
- A quike guide teaching you how to use matlab to read netCDF file and plot a figure
1. Preparation 2. A brief introduce to netCDF. 4 3. Data Structure. 4 3.1 Attrib ...
- Gleb And Pizza CodeForces - 842B
CodeForces - 842B #include<bits/stdc++.h> using namespace std; int main() { int r,d,t; double ...
- android自定义View之3D索引效果
效果图: 我的小霸王太卡了. 最近工作比较忙,今天搞了一下午才搞出来这个效果,这种效果有很多种实现方式,最常见的应该是用贝塞尔曲线实现的.今天我们来看另一种不同的实现方式,只需要用到 canvas.s ...
- Zookeeper核心工作机制(zookeeper特性、zookeeper数据结构、节点类型)
10.1 zookeeper特性 1.Zookeeper:一个leader,多个follower组成的集群. 2.全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个ser ...
- oh forever love~
npm install -g forever forever start c9sdk/server.js --listen 0.0.0.0 --port 80 -a aa:111 -w ~ To el ...
- ubuntu重装指定版本的mysql
查看错误log cat /var/log/mysql/error.log 首先彻底删除mysql,比如版本5.5 apt-get autoremove --purge mysql-server-5.5 ...
- Netty 4源码解析:服务端启动
Netty 4源码解析:服务端启动 1.基础知识 1.1 Netty 4示例 因为Netty 5还处于测试版,所以选择了目前比较稳定的Netty 4作为学习对象.而且5.0的变化也不像4.0这么大,好 ...
- 20160213.CCPP体系详解(0023天)
程序片段(01):全排列.c 内容概要:全排列密码库 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <std ...