1016 Phone Bills

news/2024/7/7 18:53:58

目录

概述:

一些小的注意点

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;
}


http://lihuaxi.xjx100.cn/news/241346.html

相关文章

java 上传的图片大小为0_JAVA技术:上传图片的缩放处理

图片上传到后&#xff0c;会根据情况将图片缩小成一个图标&#xff0c;我们可以利用java强大的图形处理功能&#xff0c;对上传的图片进行缩放处理。下面的程序使用jdk1.4中最新的ImageIO对图片进行读写。使用AffineTransform对图片进行缩放。import java.io.File&#xff1b;i…

1084 Broken Keyboard

两个注意的点 1.本题被归到散列专题下&#xff0c;但是由于是逐字符地映射到整形&#xff0c;可以直接把布尔型哈希数组的大小设置为ASCII的数量128&#xff0c;然后直接将字符作为数组下标(如果是字符串&#xff0c;才需要自己写一个哈希函数&#xff0c;将字符串映射到整形&…

浮动元素会引起的问题和你的解决办法

问题&#xff1a; &#xff08;1&#xff09;父元素的高度无法被撑开&#xff0c;影响与父元素同级的元素&#xff08;2&#xff09;与浮动元素同级的非浮动元素会跟随其后&#xff08;3&#xff09;若非第一个元素浮动&#xff0c;则该元素之前的元素也需要浮动&#xff0c;否…

DBA入门之路:由浅入深的总结学习法

有很多DBA朋友在入门时总觉得不得路径&#xff0c;长久的徘徊于门外&#xff0c;而过来人的经验又往往高屋建瓴难以落地&#xff0c;两者总觉得难以对接起来&#xff0c;如何才能解决这个问题呢&#xff1f; 我一直推荐的学习方法&#xff0c;之前在文章 DBA入门之路&#xff1…

java 判断是否为邮箱_Java判断邮箱是否存在 有返回值

public static boolean checkEmail(String email) {if (!email.matches("[\\w\\.\\-]([\\w\\-]\\.)[\\w\\-]")) {return false;}String log "";String host "";String hostName email.split("")[1];// 去掉后面的System.out.printl…

1033 旧键盘打字

1. 非常奇怪&#xff0c;明明都说了用下划线替代空格&#xff0c;但是用scanf读入的时候就会有1个测试点没通过&#xff0c;换成cin.getline就通过了 2.3种情况下对应的哈希表赋值为true。1是上来就赋值&#xff0c;2是对于大写字母把对应小写字母也赋值&#xff0c;这里注意直…

前端编程提高之旅(五)----写给大家看的css书

自实习也有几个月的时间了&#xff0c;以爱奇艺实习为敲门砖。进入了眼下这家公司。假设说当初能进爱奇艺是暂时袭击DIVCSS的话&#xff0c;眼下在这家公司体验到。不论什么技术都必须悉知原理&#xff0c;这样才干做到庖丁解牛。做一个内行的人。css属性和使用方法都摆在那里&…

flex数据绑定

2019独角兽企业重金招聘Python工程师标准>>> 1 、方法绑定 [Bindable(event"myFlagChanged")] private function isEnabled():String { if (myFlag)return true; else return ‘false; } <mx:TextArea id"myTA" text"{isEnabled()}&…