目录

概述:

一些小的注意点

AC代码


概述:

这道题是我迄今做出来的最复杂的一道PAT了,该题被归类到排序专题下,其实还涉及到大量的字符串处理等别的我暂时也说不出的知识点。

排序函数我写了两个,1是cmp,用于让记录按照时间从早到晚的顺序排列,2是cmp2,让用户按照姓名的字母顺序从小到大排列,可以说是很简单的两个函数。

结构体写了三个,分别是record,user,call。其中user包含call数组。record用于读入记录,属性对应输入。call是每一对记录(on-line和off-line),包括开始结束时间,分钟数,话费。user是每个用户,call_num代表记录的条数,用于最后的输出使用。

struct call{char startTimeExMonth[15];char endTimeExMonth[15];int call_minute = 0;double call_money = 0;
};struct user{char name[22] = "";char month[3] = ""; call calls[maxn];int call_num = 0;double total_money = 0;
}users[maxn];struct record{char name[22] = "";char time[15] = "";char state[10] = "";
}recs[maxn][maxn];

除了比较函数外还写了两个函数,getMinute输入开始和结束时间,输出总共的分钟数。getMoney输入开始、结束时间和单位话费数组,输出美元数(1美元=100美分)。

这两个函数一开始都有让我共同纠结的点,比如遇到大单位数字小,小单位数字大两个数如何相减。其实可以放心使用 x - y = (x-0)-(y-0)

int getMinute(char startTime[15],char endTime[15]){int startMonth = 0;int startDay = 0;int startHour = 0;int startMin = 0;int endMonth = 0;int endDay = 0;int endHour = 0;int endMin = 0;sscanf(startTime,"%d:%d:%d:%d",&startMonth,&startDay,&startHour,&startMin);sscanf(endTime,"%d:%d:%d:%d",&endMonth,&endDay,&endHour,&endMin);//01:02:00:01 01:04:23:59 4318return (endDay*24*60+endHour*60+endMin) - (startDay*24*60+startHour*60+startMin);
}double getMoney(char startTime[15],char endTime[15],int tolls[24]){int startMonth = 0;int startDay = 0;int startHour = 0;int startMin = 0;int endMonth = 0;int endDay = 0;int endHour = 0;int endMin = 0;sscanf(startTime,"%d:%d:%d:%d",&startMonth,&startDay,&startHour,&startMin);sscanf(endTime,"%d:%d:%d:%d",&endMonth,&endDay,&endHour,&endMin);int fullday_money = 0;//一整天的话费 for(int i=0;i<24;i++){fullday_money += 60*tolls[i];}int start_minute_money = 0;//假设从0点开始打,打到整分的话费for(int i=0;i<startHour;i++){start_minute_money += 60*tolls[i];}int end_minute_money = 0;for(int i=0;i<endHour;i++){end_minute_money += 60*tolls[i];}int startMoney = startDay*fullday_money+start_minute_money+tolls[startHour]*startMin;int endMoney = endDay*fullday_money+end_minute_money+tolls[endHour]*endMin;return (endMoney-startMoney)/100.0;
}

一些小的注意点

1. 怎样比较时间先后:由于时间是以

01:01:06:01

月:日:时:分的形式从大到小排列的字符串,所以在cmp中写strcmp即可。

2. 怎样得到一对时间,对于每一个人按照时间排好顺序的记录,判断本条是否状态为在线且下条状态为离线,注意,由于相等时strcmp返回的是0,要记得加取反符号

if(!strcmp(recs[i][j].state,"on-line")&&!strcmp(recs[i][j+1].state,"off-line")) 

3. 那么多条记录,怎样将某个人的记录归类,这是我第一次做。开辟一个二维结构体数组,第一维表示每个人,通过strcmp对比当前读入的人名和每一维第一个元素的人名,如果有则为那一行的列数加一,如果没有就增加行数。

for(int i=0;i<n;i++){bool hasFound = false;scanf("%s %s %s",name,time,state);//通过字符串比对姓名,看能否找到他for(int j=0;j<row;j++){if(strcmp(recs[j][0].name,name)==0){strcpy(recs[j][cols[j]].name,name);strcpy(recs[j][cols[j]].time,time);strcpy(recs[j][cols[j]].state,state);cols[j]++;hasFound = true;break;}}if(!hasFound){//没找到他,新开一列 strcpy(recs[row][0].name,name);strcpy(recs[row][0].time,time);strcpy(recs[row][0].state,state);cols[row]++;row++;} }

4. 一开始我的2,3测试点是错误的,看了别的博客才知道,没有进行合法性校验,在读题时把每个测试用例至少有一对记录合法理解成每个人至少有一对记录合法。正确方式是如果某人没有记录,应当不予以输出,即加入如下代码:

const double eps = 1e-3;
if(abs(users[i].total_money-0)<eps)continue;

AC代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;const int maxn = 1010;
const double eps = 1e-3;struct call{char startTimeExMonth[15];char endTimeExMonth[15];int call_minute = 0;double call_money = 0;
};struct user{char name[22] = "";char month[3] = ""; call calls[maxn];int call_num = 0;double total_money = 0;
}users[maxn];struct record{char name[22] = "";char time[15] = "";char state[10] = "";
}recs[maxn][maxn];bool cmp(record a,record b){return strcmp(a.time,b.time)<0;
}bool cmp2(user a,user b){return strcmp(a.name,b.name)<0;
}int getMinute(char startTime[15],char endTime[15]){int startMonth = 0;int startDay = 0;int startHour = 0;int startMin = 0;int endMonth = 0;int endDay = 0;int endHour = 0;int endMin = 0;sscanf(startTime,"%d:%d:%d:%d",&startMonth,&startDay,&startHour,&startMin);sscanf(endTime,"%d:%d:%d:%d",&endMonth,&endDay,&endHour,&endMin);//01:02:00:01 01:04:23:59 4318return (endDay*24*60+endHour*60+endMin) - (startDay*24*60+startHour*60+startMin);
}double getMoney(char startTime[15],char endTime[15],int tolls[24]){int startMonth = 0;int startDay = 0;int startHour = 0;int startMin = 0;int endMonth = 0;int endDay = 0;int endHour = 0;int endMin = 0;sscanf(startTime,"%d:%d:%d:%d",&startMonth,&startDay,&startHour,&startMin);sscanf(endTime,"%d:%d:%d:%d",&endMonth,&endDay,&endHour,&endMin);int fullday_money = 0;//一整天的话费 for(int i=0;i<24;i++){fullday_money += 60*tolls[i];}int start_minute_money = 0;//假设从0点开始打,打到整分的话费for(int i=0;i<startHour;i++){start_minute_money += 60*tolls[i];}int end_minute_money = 0;for(int i=0;i<endHour;i++){end_minute_money += 60*tolls[i];}int startMoney = startDay*fullday_money+start_minute_money+tolls[startHour]*startMin;int endMoney = endDay*fullday_money+end_minute_money+tolls[endHour]*endMin;return (endMoney-startMoney)/100.0;
}int main(){int row = 0;//行,二维结构体数组的第一维下标,代表某个用户int cols[maxn] = {0};//记录每一行的列数 //读入每个时段的电话费int tolls[24];for(int i=0;i<24;i++){scanf("%d",&tolls[i]);}//读入记录的数量int n;scanf("%d",&n);//开始读入记录,同一个用户数组下标的第一维得是一样的char name[22] = "";char time[15] = "";char state[10] = "";for(int i=0;i<n;i++){bool hasFound = false;scanf("%s %s %s",name,time,state);//通过字符串比对姓名,看能否找到他for(int j=0;j<row;j++){if(strcmp(recs[j][0].name,name)==0){strcpy(recs[j][cols[j]].name,name);strcpy(recs[j][cols[j]].time,time);strcpy(recs[j][cols[j]].state,state);cols[j]++;hasFound = true;break;}}if(!hasFound){//没找到他,新开一列 strcpy(recs[row][0].name,name);strcpy(recs[row][0].time,time);strcpy(recs[row][0].state,state);cols[row]++;row++;} }//对所有列进行排序for(int i=0;i<row;i++){sort(recs[i],recs[i]+cols[i],cmp);}for(int i=0;i<row;i++){//对于每一个人
//      printf("%s %c%c\n",recs[i][0].name,recs[i][0].time[0],recs[i][0].time[1]); //赋予姓名 strcpy(users[i].name,recs[i][0].name);for(int j=0;j<2;j++){users[i].month[j]=recs[i][0].time[j];}double total_money = 0;double call_money = 0;int call_minute = 0;int call_num = 0;char startTime[15] = "";char endTime[15] = "";for(int j=0;j<cols[i]-1;j++){if(!strcmp(recs[i][j].state,"on-line")&&!strcmp(recs[i][j+1].state,"off-line")){strcpy(startTime,recs[i][j].time);strcpy(endTime,recs[i][j+1].time);char startTimeExMonth[15] = "";for(int i=0;i<8;i++){startTimeExMonth[i] = startTime[3+i];}char endTimeExMonth[15] = "";for(int i=0;i<8;i++){endTimeExMonth[i] = endTime[3+i];}users[i].calls[call_num].call_minute = getMinute(startTime,endTime);users[i].calls[call_num].call_money = getMoney(startTime,endTime,tolls);total_money += getMoney(startTime,endTime,tolls);strcpy(users[i].calls[call_num].startTimeExMonth,startTimeExMonth);strcpy(users[i].calls[call_num].endTimeExMonth,endTimeExMonth);call_num++;}}users[i].call_num = call_num;users[i].total_money = total_money;}//对用户按照总的话费进行排序 sort(users,users+row,cmp2);//输出for(int i=0;i<row;i++){if(abs(users[i].total_money-0)<eps)continue;printf("%s %s\n",users[i].name,users[i].month);for(int j=0;j<users[i].call_num;j++){printf("%s %s %d $%.2f\n",users[i].calls[j].startTimeExMonth,users[i].calls[j].endTimeExMonth,users[i].calls[j].call_minute,users[i].calls[j].call_money);}printf("Total amount: $%.2f\n",users[i].total_money);} return 0;
}

1016 Phone Bills相关推荐

  1. PAT甲级1016 Phone Bills :[C++题解]字符串处理(复杂题)(C语言格式化读入、输出很便利!!!)

    文章目录 题目分析 题目链接 题目分析 原题: 长途电话公司按以下规则向客户收费: 拨打长途电话每分钟要花费一定的费用,具体收费取决于拨打电话的时间. 客户开始拨打长途电话的时间将被记录,客户挂断电话 ...

  2. 1016. Phone Bills (25)

    时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue 去掉非法数据计算账单 A long-distance telep ...

  3. 1016 Phone Bills (25)(25 分)

    1 题目 2 解题思路 3 AC代码 4 总结 1 题目 A long-distance telephone company charges its customers by the followin ...

  4. 【注意点分析】1016 Phone Bills (25 分)

    立志用最少的代码做最高效的表达 PAT甲级最优题解-->传送门 A long-distance telephone company charges its customers by the fo ...

  5. PAT 1016 Phone Bills (25分) 逻辑较为复杂 sort() + map

    题目 A long-distance telephone company charges its customers by the following rules: Making a long-dis ...

  6. 1016 Phone Bills (25 分) 【未完成】【难度: 中 / 知识点: 模拟】

    https://pintia.cn/problem-sets/994805342720868352/problems/994805493648703488

  7. PAT (Advanced Level) 1016 Phone Bills(恶心模拟)

    题目链接:点击查看 题目大意:模拟电话收费规则: 每个时间段的收费不同,时间段分为:00:00-01:00,01:00-02:00诸如此类 最开始给出的单价是每分钟的单价 最后输出每个用户的电话费 题 ...

  8. 1016 Phone Bills (25分)

    这个题相对复杂一点,读题用了20分钟,然后就是疯狂写代码,其实这个主要是计算费用复杂一点,其他倒是还好,第一遍提交有测试点1,2没过,回头看了一眼代码觉得计算不可能出错,然后一分析就是测试点1,2很显 ...

  9. PAT甲级 1016 Phone Bills(时间差)

    Link 题意: 远程电话的收费是按照每分钟来计费的,现在告诉你一天24小时中每分钟的收费标准,以及n条通话记录,试求出每个人该月的消费账单. 只有开始记录没有结束记录的通话不计费,反之亦然.保证所有 ...

最新文章

  1. “比特币耶稣”Roger Ver:比特币现金分叉没有技术论据支持
  2. 测试CH340C的功能,制作MicroPython ESP8266,ESP32下载器
  3. vue是什么_什么是VUE?vue有什么作用?
  4. 如何计算机操作维护培训,电脑基本操作培训教材.ppt
  5. Dubbo与Spring Cloud
  6. 12011.linux之看门狗应用开发
  7. jira confluence 作用 ppt_有没有一个PPT技巧让自己觉得人生都亮了?
  8. Button switch..case 语句监听按钮点击的方法。。下面这方法好。
  9. word字间距异常处理方式
  10. 中南大学计算机学院伍逸凡,关于公布2017年湖南省大学生力学竞赛等15项学科竞赛结果的通知...
  11. 广义线性模型解读必看文章
  12. 八仙过海,四种同步(Java中的四种同步类)
  13. java 向路由器发送报文_9.IP选路 - loda0128的个人空间 - OSCHINA - 中文开源技术交流社区...
  14. python定时更换桌面壁纸
  15. 最新转转验机源码+独立后台管理
  16. 虚拟机的迁移和复制分发
  17. 2022广东省安全员A证第三批(主要负责人)考试题库模拟考试平台操作
  18. 回归评价指标:均方误差根(RMSE)和R平方(R2)
  19. 苹果发布了没有太多更新的 iOS 13 beta 8;一次编码、到处运行;SwiftUI 的两个特性;如何让网站加载更快...
  20. Academic Torrents - 学术种子资源下载网

热门文章

  1. 小程序订阅消息 订阅消息开发
  2. 微信小程序自定义轮播图滚动样式 自定义组件轮播图的实现
  3. VMware前路难测,多个厂家群雄逐鹿
  4. postfix邮箱服务
  5. SQL Server-流程控制 5,Goto 语句
  6. LAMP兄弟连PHP课程学习笔记 第二天 PHP中使用变量
  7. Java数据访问对象模式
  8. 揭秘vue——vue-cli3全面配置
  9. 字符串转换成utf-8编码
  10. Android Eclipse之Git插件安装、配置、提交、修改、冲突、查看历史、覆盖。