题目大意:
给出24h中每个小时区间内的资费,给出N个通话记录点,每个记录点记录了姓名,当前时刻:(月:日:时:分)通话开始(on-line)结束:(off-line) 对每个人的有效通话记录进行资费计算。
”有效通话记录“:可以理解为对同一个人的通话记录按照时间先后顺序排序后一对连续的on-line off-line
思路:
对所有记录进行排序,并且判断是否存在有效通话记录,如果有则输出有效通话记录,同时计算时长,统计资费
输入信息结构体定义:
struct Record {
char name[25];
int month, dd, hh, mm;
bool status;//statue==ture:on-line status==false :off-line
}rec[maxn], temp;
1.排序cmp函数:
1)用户名不同,以用户名从小到大。
2) 用户名相同,以时间从小到大,即月份,日期,小时,分钟的顺序有效到大的顺序。
bool cmp(Record a, Record b) {
int s = strcmp(a.name, b.name);
if (s != 0)return s < 0;
else if (a.month != b.month)return a.month < b.month;
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;
}
2.判断是否存在有效通话记录(即是否需要输出)
int on,int next;//on表示该用户第一条记录,即开始,next表示当先下一条记录
while(on<总数){
int needPrint=0;//needPrint=0为初值,=1为匹配到on-line =2表示需要输出
next=on;
while(next<总数&&姓名匹配还是当前用户){
if(needPrint==0&&当前记录状态为on-line)needPrint=1;
else if(needPrint==1&&当前记录状态为off-line)needPrint=2;//配对成功表示需要输出
next++;
}
if(needPrint<2){//如果没有匹配到的,就继续下一个用户
on=next;
continue;
}
}
3.如果needPrint==2,输出有效记录
遍历该用户列表,找见当前记录为on-line并且下一条记录为off-line的记录,对该记录进行资费统计
(资费统计)可以统计一共有多少分钟,根据每个时段的的价位累加
用来计算两个时间之间的差值的算法(常考)
//也可以推到年月日,计算天数
while(start.day < end.day || start.hour < end.hour || start.minute < end.minute){
start.minute++;
if(start.minute == 60){
start.minute = 0;
start.hour++;
}
if(start.hour = 24){
start.hour = 0;
start.day++;
}
}
本题的版本:
void get_ans(int on, int off, int &time, int &money) {
temp = rec[on];
while (temp.dd < rec[off].dd || temp.hh < rec[off].hh || temp.mm < rec[off].mm) {
time++;
money += toll[temp.hh];
temp.mm++;
if (temp.mm >= 60) {
temp.mm = 0;
temp.hh++;
}
if (temp.hh >= 24) {
temp.hh = 0;
temp.dd++;
}
}
}
最后累加该用户的所有通话记录的总费用并输出。(资费单价是美分,要换算成美元)
4.进行下一个用户
AC代码:
//PAT_A 1016
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1010;
int toll[25];
struct Record {
char name[25];
int month, dd, hh, mm;
bool status;
}rec[maxn], temp;
bool cmp(Record a, Record b) {
int s = strcmp(a.name, b.name);
if (s != 0)return s < 0;
else if (a.month != b.month)return a.month < b.month;
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 = rec[on];
while (temp.dd < rec[off].dd || temp.hh < rec[off].hh || temp.mm < rec[off].mm) {
time++;
money += toll[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", &toll[i]);
}
int n;
char line[10];
scanf("%d", &n);
for (int i = 0; i < n; i++) {
(void)scanf("%s", rec[i].name);
(void)scanf("%d:%d:%d:%d", &rec[i].month, &rec[i].dd, &rec[i].hh, &rec[i].mm);
(void)scanf("%s", line);
if (strcmp(line, "on-line") == 0)rec[i].status = true;
else rec[i].status = false;
}
sort(rec, rec + n, cmp);
int on = 0, off, next;
while (on < n) {//循环处理单个用户的所有记录
int needPrint = 0;//表示该用户是否需要输出
next = on;//从当前位置开始寻找下一个用户,next中存储的是下一个用户的首地址
while (next < n && strcmp(rec[next].name, rec[on].name) == 0) {
if (needPrint == 0 && rec[next].status == true)needPrint = 1;//找到on 置1
else if (needPrint == 1 && rec[next].status == false)needPrint = 2;//on之后找到off 置2
next++;
}
if (needPrint < 2) {//没有配对的on-off
on = next;
continue;
}
int AllMoney = 0;
printf("%s %02d\n", rec[on].name, rec[on].month);
while (on < next) {
while (on < next - 1 && !(rec[on].status == true && rec[on + 1].status == false))on++;//找到连续的on-off
off = on + 1;
if (off == next) {//表示已经到了最后一个用户,开始处理下一个用户
on = next;
break;
}
printf("%02d:%02d:%02d ", rec[on].dd, rec[on].hh, rec[on].mm);
printf("%02d:%02d:%02d ", rec[off].dd, rec[off].hh, rec[off].mm);
int time = 0, money = 0;
get_ans(on, off, time, money);
AllMoney += money;
printf("%d $%.2f\n", time, money / 100.0);
on = off + 1;
}
printf("Total amount: $%.2f\n", AllMoney / 100.0);
}
return 0;
}