pat-甲级1016-Phone Bills

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/richenyunqi/article/details/79307384

欢迎访问我的pat甲级题解目录哦https://blog.csdn.net/richenyunqi/article/details/84981078

题目描述

算法设计

先用一个长度为25的数组price读入一天内各个小时段的话费单价,接着定义一个Time类,包含月日时分的时间信息以及是online还是offline,此外为了方便比较,我还定义了一个域用来存储距0日0时0分的分钟数。为了能够用set进行自然排序,我还在Time类中重载了<运算符,综上,类的定义代码如下:

struct Time{//定义时间类
    int month,day,hour,minute,time,online=0;//月日时分信息、距0日0时0分的分钟数、指明这一时间是online还是offline
    bool operator <(const Time&t)const{//重载<运算符
        return this->time<t.time;
    }
};

1. 如何在set<Time>中找出所有的有效的话费记录

如题目要求的,只有相邻的两个online和offline的通话记录时间之间才能算做一个有效的通话记录,由于set<Time>已经按时间自然排序,我们只需在set<Time>中找出相邻的两个online和offline即可。由于set无法进行随机访问,我们只能借助于迭代器来访问set,可以定义两个迭代器 j 和 jnext 分别指向当前set<Time>中的对象和紧邻的下一个set<Time>中的对象,如果 j->online为true且jnext->online为false说明找到了一组有效的通话记录,否则++j;++jnext,直至将整个set遍历完成就能找出所有有效的通话记录。

2. 如何计算两个Time对象t1,t2(假设t1早于t2)之间通话的时间 time 和通话的费用sumbill(price数组存储了一天内各个小时段的话费)

由于存储了每一个Time对象距0日0时0分的分钟数,所以time=t2.time-t1.time

利用类似的原理,我们可以分别计算出t1、t2到某一天的0时0分所用话费,两者作差,即可计算出sumbill。为了方便计算通话一天所用话费,可以在读取一天各个小时段话费单价时,逐一进行加和并储存到price[24]中,那么通话一天所用话费即为price[24]*60*天数。

呢么计算当期时间到day日0时0分的话费的代码如下:

double compute(Time t,int day){//计算当前时间到day日0时0分所用话费
    double bill=0.0;
    for(int i=0;i<t.hour;++i)
        bill+=60*price[i];
    return bill+t.minute*price[t.hour]+price[24]*60*(t.day-day);
}

其中day可以直接赋值为t1.day。

解决了以上的数据结构选取和一些算法问题,整道题就容易解决了

注意点

  1. 如果某一个人虽然有账单,但是没有找到有效的通话记录,这个人不予输出
  2. 输入的一天内各个小时段的话费单位是美分/分钟,所以在计算的时候一个小时的话费应该是60*price[i],另外输出费用要按美元计算,所以要除以100,不妨在输入一天内各个小时段的话费时就直接进行除以100的操作
  3. 输出月、日、时、分都必须有两位数字不够的要在高位补0

C++代码

#include<bits/stdc++.h>
using namespace std;
struct Time{//定义时间类
    int month,day,hour,minute,time,online=0;//月日时分信息、距0日0时0分的分钟数、指明这一时间是online还是offline
    bool operator <(const Time&t)const{//重载<运算符
        return this->time<t.time;
    }
};
double price[25];//存储一天内各个小时段的话费单位是美元/分钟
double compute(Time t,int day){//计算当前时间到day日0时0分所用话费
    double bill=0.0;
    for(int i=0;i<t.hour;++i)
        bill+=60*price[i];
    return bill+t.minute*price[t.hour]+price[24]*60*(t.day-day);
}
int main(){
    for(int i=0;i<24;++i){//读取一天内各个小时段的话费
        scanf("%lf",&price[i]);
        price[i]/=100.0;//化为美元
        price[24]+=price[i];
    }
    int N;
    scanf("%d",&N);
    map<string,set<Time>>bill;//存储每个人的名字和对应的话费时间
    for(int i=0;i<N;++i){//读取账单
        string s1,s2;
        Time t;
        cin>>s1;
        scanf("%d:%d:%d:%d",&t.month,&t.day,&t.hour,&t.minute);
        t.time=(t.day*24+t.hour)*60+t.minute;
        cin>>s2;
        if(s2=="on-line")
            t.online=1;
        bill[s1].insert(t);
    }
    for(auto i=bill.cbegin();i!=bill.cend();++i){//查找有效的话费记录并就算用时与话费并输出
        bool output=false;//该人的话费记录是否需要输出/是否有有效的话费记录
        double sumBill=0.0;//该人的话费总额
        for(auto j=(i->second).cbegin();j!=(i->second).cend();++j){//定义set的迭代器j
            auto jnext=j;//定义指向j指向的下一个对象的迭代器
            ++jnext;
            for(;jnext!=(i->second).cend()&&!(j->online&&!jnext->online);++j,++jnext);//查找有效的话费记录
            if(jnext!=(i->second).cend()){//如果查找到了
                if(!output){//还没有输出过姓名的月份进行输出,并通过修改output变量标明该人的话费记录需要输出
                    output=true;
                    printf("%s %02d\n",(i->first).c_str(),j->month);
                }
                printf("%02d:%02d:%02d %02d:%02d:%02d ",j->day,j->hour,j->minute,jnext->day,jnext->hour,jnext->minute);//输出话费账单起止时间
                int t=jnext->time-j->time;//计算话费
                double bill=compute(*jnext,j->day)-compute(*j,j->day);//计算话费账单用时
                sumBill+=bill;//加到话费总额上
                printf("%d $%.2f\n",t,bill);//输出
            }
        }
        if(output)//如果该人的话费记录需要输出,输出话费总额
            printf("Total amount: $%.2f\n",sumBill);
    }
    return 0;
}

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试