PAT题解——1016. Phone Bills (25)

来源:互联网 发布:如何删除淘宝精选 编辑:程序博客网 时间:2024/06/14 09:47

[声明]:由于本人在使用《算法笔记》的过程中有部分题解和《算法笔记》上的解法不同,特此作为记录,同时可以提供新的思路供读者参考;
1. 题目链接:https://www.patest.cn/contests/pat-a-practise/1016
2. 解题思路:
① 用结构体存储姓名、月、日、时、分以及状态(0表示off-line,1表示on-line);
②对所有结构体数组内容进行排序,先按照姓名升序,使得相同姓名的排在一起,再按照通话时刻升序
③对排好序的数组进行从头扫描,找出有效配对:即当前的姓名和下一个姓名相同,当前的状态为1,下一个状态为0;若不是有效配对,继续扫描;
④找到有效配对后,根据判断当前的姓名是否输出从而选择性输出姓名,再依次输出两个时刻,调用lasting函数计算并输出总持续时间,调用fee函数计算并输出对应时间段的费用;并加入total_amount;
⑤若当前姓名与下一个姓名不同,说明当前姓名total_amount已经计算完毕,输出即可;
3.AC代码:

#include<stdio.h>#include<cstring>#include<algorithm>using namespace std;const int maxn=1010;struct r{    char name[25];    int mo,dd,hh,mm;    int status;  //记录状态on-line或者off-line }re[maxn];bool cmp(r a,r b){    if(strcmp(a.name,b.name)) return strcmp(a.name,b.name)<0;    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;}int toll[24];  //用于存储一天中每个小时对应的费用 ,单位cent/min int lasting(int d,int h,int m,int dd,int hh,int mm){  //计算持续时间,d,h,m表示开始的日,时,分;dd,hh,mm表示结束时的日,时,分     int time=0;  //记录持续的时间,单位:分     while(d!=dd||h!=hh||m!=mm){   //思路:通过不断将初始的m+1,同时time+1,最终和结束时间完全相同即可         ++m;++time;        if(m==60){            m=0;            ++h;        }        if(h==24){            h=0;            ++d;        }    }    return time;}double fee(int d,int h,int m,int dd,int hh,int mm){ //计算持续时间内的花费,d,h,m表示开始的日,时,分;dd,hh,mm表示结束时的日,时,分     double f=0;  //记录话费     while(d!=dd||h!=hh||m!=mm){        ++m;f+=toll[h];   //加上对应小时的话费         if(m==60){            m=0;            ++h;        }        if(h==24){            h=0;            ++d;        }    }    return f/100;  //cent单位转换为$ }int main(){    int N; //总记录条数     for(int i=0;i<24;i++) scanf("%d",&toll[i]); //输入24小时对应的话费标准,单位cent/min     scanf("%d",&N);     char temp[10]; //临时记录"on-line"还是"off-line"     for(int i=0;i<N;i++){        scanf("%s %d:%d:%d:%d %s",re[i].name,&re[i].mo,&re[i].dd,&re[i].hh,&re[i].mm,temp);        if(!strcmp(temp,"on-line")) re[i].status=1; //若是on-line 则状态变为1,否则为0         else re[i].status=0;    }    sort(re,re+N,cmp); //总体进行排序,相同名字的排一起并升序,然后按照时间先后排序     char last_name[20];  //暂时不用理解     double total=0;   //记录总话费     for(int i=0;i<N;i++){        if(strcmp(re[i].name,re[i+1].name)==0&&re[i].status==1&&re[i+1].status==0){  //有效配对              if(strcmp(re[i].name,last_name)){      //如果同名字的人有1对以上的有效配对 ,第二次不用输出姓名,所以用last_name存储上次输出的姓名                  printf("%s %02d\n",re[i].name,re[i].mo);  //并判断本次有效配对的姓名和上次的是否相同;                 strcpy(last_name,re[i].name);                        }            printf("%02d:%02d:%02d",re[i].dd,re[i].hh,re[i].mm);            printf(" %02d:%02d:%02d",re[i+1].dd,re[i+1].hh,re[i+1].mm);            printf(" %d",lasting(re[i].dd,re[i].hh,re[i].mm,re[i+1].dd,re[i+1].hh,re[i+1].mm)); //调用函数计算持续时间,单位min             double temp_fee=fee(re[i].dd,re[i].hh,re[i].mm,re[i+1].dd,re[i+1].hh,re[i+1].mm);   //调用函数计算此时间段的费用,单位$             printf(" $%.2f\n",temp_fee);             total+=temp_fee;  //计算总费用         }        if(strcmp(re[i].name,re[i+1].name)&&total){  //下一个名字不同,同时总费用不为0,则输出目前这个人的Total amount             printf("Total amount: $%.2f\n",total);            total=0; //总费用重新置零,用于下一个人的总费用计算         }    }}