题意:
第一行 给出24h中每个小时区间内的资费(分钟为单位)!!!注意时间格式是(月 日 时 分),并给出N个通话记录点,每个通话记录点都记录了姓名、当前时刻(月;日;时;分)以及其属于通话开始(on-line)或是通话结束(off-line)。现在对每个人的有效通话记录进行资费计算,有效通话记录是指同一个用户能够配对的所有on-line 和off-line,而这样的配对需满足:在按时间排序后,两条配对的on-line和off-line对应时间内不能出现其他的on-line和off-line记录。
输出要求:按姓名的字典序从小到大的顺序输出存在有效通话记录的用户,对单个用户来说,要输出他的姓名、账单月份(保证单个用户的所有记录都在同一个月产生)以及有效通话记录的时长和花费,最后输出他的总资费。资费的输出要进行转换,即把cent转换为dollar,所以结果要除以100。
样例解释:
总共三个用户 按字典序从小到大是CYJJ、CYLL、aaa(小写字母字典序大A65 a97),各自的情况
CYJJ: 只有一对匹配的记录,恰好可以配对,010559-010700 时长为61min,花费为(10*1+60*20)/100.0=12.10
CYLL:有两对匹配的记录,01 0601-01 0803 28 1605-28 1541时长分别为122min,24min。
花费计算:
第一个 八点到八点三分 3*20 六点零一到八点是(59+60)*20 一共是 2440,再除以100是24.40
第二个 十五点四十一分到十六点 (19*15+ 十六点到十六点零五5*20)/100 = 3.85
aaa: 题目描述: 每一个记录都会与客户就是时间轴上的下一个记录匹配,没有匹配上的就删掉,所以010103下一个时间是020001 但这两个时间同为online,不能匹配,所以删掉010103.然后020001开始匹配 然后匹配到了下一个042359,
计算 02号00:00到05号00:00恰好是三天(60*6*10+60*3*20+60*7*15+60*2*20+60*30+60*15*2+60*10*3)/100 *3 再减去两个一分钟 2*1*10 得到结果为638.80
思路:
1 对所有记录排序 2 对每个用户判断是否存在有效的通话记录。 3 有则输出有效通话记录并计算资费。
具体:
一 定义结构体Record 存放单条记录的用户名 月 日 时 分 以及通话状态(online offline )
数据预处理(就是先把记录排好序) 根据题目要求写bmp函数,要求如下:
1 如果用户名不同 按字典序从小到大(大写字母字典序小)排序。
2 否则(用户名相同) 月份不同 按月份从小到大排序
3 else if 天数不同 按天数从小到大排序
4 esle if 小时不同 按小时从小到大排序
5 else 分钟不同 按分钟从小到大排序
二 找寻每个记录的有效通话时间: 必须保证online和offline先后出现。
!!!!!!!方法如下!!!!!!!!!!!!
设置int型变量 needPrint 表示是否存在有效通话记录,初值为0,遍历该用户的所有记录。如果在needPrint为0的情况下遇到online的记录 needPrint就为1,如果needPrintf为1的情况下,遇到offline,就置为2。 这样遍历结束之后 如果为2的话,说明用户存在有效通话记录,同时设置int型变量next,表示下一个用户的首记录在数组中的下标,并在遍历过程中对其进行累加,这样当遍历结束时,就得到next作为下一个用户的标识。
三 输出所有有效通话记录,条件:online的数组下标和offline的数组下标只相差1时才配对,反复寻找当前下标i与其下一个元素的下标i+1满足前者online 而后者offline即可。 找到即输出。
四 费用的计算方法 对已知的起始时间和终止时间,只需要不断将起始时间加1 判断其是否加到终点。
也可以把时间转换为分 再做差。
注意点:
1 配对必须保证online和offline是时间上相邻的两条记录。
2 题目保证整个输入至少有一对有效通话记录,但不保证每个用户都有。因此没有的不输出。
3 题目保证了单组数据中的月份相同。
4 边界数据
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int rate[25];
struct record{
char name[25];
int yy,dd,hh,mm;
bool status;//true online
}re[1010],temp;
bool cmp(record a,record b){
int s = strcmp(a.name,b.name);
if(s!=0) return s<0;
else if(a.yy!=b.yy) return a.yy<b.yy;
else if(a.dd!=b.dd) return a.dd<b.dd;
else if(a.hh!=b.hh) return a.hh<b.hh;
else return a.mm<b.mm;
}
void get_ans(int on,int off,int& time,int& money){
temp=re[on];
while(temp.dd<re[off].dd||temp.hh<re[off].hh||temp.mm<re[off].mm){
time++;//min
money+=rate[temp.hh];
temp.mm++;
if(temp.mm>=60){
temp.mm=0;
temp.hh++;
}
if(temp.hh>=24){
temp.hh=0;
temp.dd++;
}
}
}
int main(){
for(int i=0;i<24;i++){
scanf("%d",&rate[i]);
}
int n;
scanf("%d",&n);
char line[10];
for(int i=0;i<n;i++){
scanf("%s ",re[i].name);
scanf("%d:%d:%d:%d",&re[i].yy,&re[i].dd,&re[i].hh,&re[i].mm);
scanf("%s",line);
if(strcmp(line,"on-line")==0) re[i].status =true;
else re[i].status =false;
}
sort(re,re+n,cmp);
int on=0,off,next;
while(on<n){
int needprintf = 0;
next=on;
while(next<n&&strcmp(re[next].name,re[on].name)==0){//一个用户
if(needprintf==0&&re[next].status==true){
needprintf=1;
}else if(needprintf==1&&re[next].status==false){
needprintf=2;
}
next++;
}
if(needprintf<2){//如果遍历完这一个用户后,没有匹配的,即needprintf不是2,则继续下一个用户
on =next;
continue; //执行下一个轮回,即不打印这个用户,判断下一个!
}
int Allmoney =0;
printf("%s %02d\n",re[on].name,re[on].yy);
while(on<next){//未到边界且不满足条件就继续找下一个
while(on<next-1&&!(re[on].status==true&&re[on+1].status==false)){
on++;
}//此事不满足while条件的on 就是需要的on值
off = on+1;
if(off==next){
on =next;//如果查询完这个用户的所有记录,on值为最后一条记录,再加一就是下一条记录的开始
break;//打印完这个用户的跳出找寻的循环,先打印总金额,再进入判断是否打印-找打印-打印的循环
}
printf("%02d:%02d:%02d ",re[on].dd,re[on].hh,re[on].mm);
printf("%02d:%02d:%02d ",re[off].dd,re[off].hh,re[off].mm);
int time=0,money=0;
get_ans(on,off,time,money);//这个money只是一次匹配成功的前
Allmoney+=money;
printf("%d $%.2f\n",time,money/100.0);
on=off+1;//打印完一个配对,从off+1开始再找
}
printf("Total amount: $%.2f\n",Allmoney/100.0);
}
return 0;
}