对电话账单来说,春季和秋季的标准时间与夏时制时间的转换会带来有意思的问题。春季,这种转换发生在(3月末,4月初的)星期日凌晨 2:00时,这时时钟要设置为凌晨3:00 时。对称的转换通常发生在 10 月最后一个星期日,时钟要从2:59:59调回到2:00:00。
请为采用以下费率计算用户的每月通话费:
(1)通话时间<=20 分钟时,每分钟收费 0.05 美元,通话时间不到 1 分钟时按 1 分钟计算。
(2)通话时间>20 分钟时,收费 1.00 美元,外加每分钟 0.10 美元,超过 20 分钟的部分,不到 1 分钟时按 1 分钟计算。
假设:
(1)通话计费时间从被叫方应答开始计算,到呼叫方挂机时结束。
(2)通话时间的秒数四舍五入到分钟。
(3)没有超过 20 个小时的通话
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> using namespace std; struct record { int smonth,sday,shour,sminute,ssecond; int emonth,eday,ehour,eminute,esecond; }; class day//mainly to label which days are sunday { private: bool is_sunday; public: day() { setsunday(false); } bool getsunday() { return is_sunday; } bool setsunday(bool value) { is_sunday=value; return true; } }; class calendar { private: day year[366]; //break1 is the last sunday before April(4);while break2 is the last sunday before November(11) int break1=31+28+31,break2=31+28+31+30+31+30+31+31+30+31; bool is_leapyear; public: calendar(int years) { is_leapyear=false; for(int i=1;i<=366;i++) { if(i%7==0) { year[i].setsunday(true); } } if((years%4==0&&years%100!=0)||years%400==0) { break1++; is_leapyear=true; } } bool showdate(int day)//to present if this day is sunday { return year[day].getsunday(); } int refresh_break1and2(int *a,int *b) { for(int i=break1;i>0;i--) { if(year[i].getsunday()) { break1=i; break; } } for(int i=break2;i>0;i--) { if(year[i].getsunday()) { break2=i; break; } } *a=break1;*b=break2; return 1; } int findday(int month,int today,int *result) { int days[12]={31,28,31,30,31,30,31,31,30,31,30,31}; int resul; if(is_leapyear) days[1]=29; for(int i=1;i<=month;i++) { resul+=days[i]; } resul+=today; *result=resul; return 1; } }; double calculate_fee() { double totalminute,totalfee; int years,break1,break2; record rec;//record for temporary cout<<"input year:"; cin>>years; calendar telefee(years); //testing sample /* for(int i=0;i<365;i++) cout<<telefee.showdate(i)<<endl; */ telefee.refresh_break1and2(&break1,&break2); //cout<<break1<<' '<<break2<<endl; cout<<"input your telephone record:"; while(scanf("%d %d %d %d %d",&rec.smonth,&rec.sday,&rec.shour,&rec.sminute,&rec.ssecond)==5&&rec.smonth&& scanf("%d %d %d %d %d",&rec.emonth,&rec.eday,&rec.ehour,&rec.eminute,&rec.esecond)==5&&rec.emonth) { if(rec.smonth!=rec.emonth) { cout<<"Crossing the month error!"<<endl; continue; } int month=rec.emonth-rec.smonth,day=rec.eday-rec.sday,hour=rec.ehour-rec.shour,minute=rec.eminute-rec.sminute,second=rec.esecond-rec.ssecond; if(month>0) cout<<"long time error"<<endl; if(day>0) cout<<"long time error"<<endl; if(hour<0) hour=0; if(minute<0) minute=0; if(second<0) second=0; if(second>0) minute++; totalminute=totalminute+hour*60+minute; int num;//the total num of the day during this year; telefee.findday(rec.smonth,rec.sday,&num); if(num==break1) minute-=60; telefee.findday(rec.smonth,rec.sday,&num); if(num==break2) minute+=60; } if(totalminute<=20) totalfee=totalminute*0.05; else { totalfee=1+(totalminute-20)*0.1; } return totalfee; } int main() { cout<<"final fee:$"<<calculate_fee()<<endl;; return 0; }
这段代码前半部分处理日期主要是使用面向对象思想来写,按照万物皆为对象的思想全部代码本都可以用面向对象去写,但是为了简化整体的耦合性,还是决定计费使用面向过程描述。按照经验,凡面向过程的程序需求对代码水平要求不高。计费部分我的想法是通过new一个日历对象,调用该对象内部的方法去计算三月最后的星期日和十月最后的星期日分别处于本年的第几天,然后调用日历类的方法去检测输入的每一个日期处于本年的第几天,这样的话,在判断日期是否属于转换的那一天就有了判断依据了。解决了这个主要的大问题后面就没有什么可说的了。
tz@COI HZAU
2018/3/27