PAT甲级 1016 Phone Bills(测试点1、2、3)

前言:

完全通过这题大概花了两个半小时(有参考别人的测试点解析),因此想记录一下自己写的代码,有很多可以优化的地方,希望可以有评论提出,我会进行改正。

A long-distance telephone company charges its customers by the following rules:

Making a long-distance call costs a certain amount per minute, depending on the time of day when the call is made. When a customer starts connecting a long-distance call, the time will be recorded, and so will be the time when the customer hangs up the phone. Every calendar month, a bill is sent to the customer for each minute called (at a rate determined by the time of day). Your job is to prepare the bills for each month, given a set of phone call records.

Input Specification:

Each input file contains one test case. Each case has two parts: the rate structure, and the phone call records.

The rate structure consists of a line with 24 non-negative integers denoting the toll (cents/minute) from 00:00 - 01:00, the toll from 01:00 - 02:00, and so on for each hour in the day.

The next line contains a positive number N (≤1000), followed by N lines of records. Each phone call record consists of the name of the customer (string of up to 20 characters without space), the time and date (MM:dd:HH:mm), and the word on-line or off-line.

For each test case, all dates will be within a single month. Each on-line record is paired with the chronologically next record for the same customer provided it is an off-line record. Any on-line records that are not paired with an off-line record are ignored, as are off-line records not paired with an on-line record. It is guaranteed that at least one call is well paired in the input. You may assume that no two records for the same customer have the same time. Times are recorded using a 24-hour clock.

Output Specification:

For each test case, you must print a phone bill for each customer.

Bills must be printed in alphabetical order of customers' names. For each customer, first print in a line the name of the customer and the month of the bill in the format shown by the sample. Then for each time period of a call, print in one line the beginning and ending time and date (dd:HH:mm), the lasting time (in minute) and the charge of the call. The calls must be listed in chronological order. Finally, print the total charge for the month in the format shown by the sample.

Sample Input:

10 10 10 10 10 10 20 20 20 15 15 15 15 15 15 15 20 30 20 15 15 10 10 10
10
CYLL 01:01:06:01 on-line
CYLL 01:28:16:05 off-line
CYJJ 01:01:07:00 off-line
CYLL 01:01:08:03 off-line
CYJJ 01:01:05:59 on-line
aaa 01:01:01:03 on-line
aaa 01:02:00:01 on-line
CYLL 01:28:15:41 on-line
aaa 01:05:02:24 on-line
aaa 01:04:23:59 off-line

Sample Output:

CYJJ 01
01:05:59 01:07:00 61 $12.10
Total amount: $12.10
CYLL 01
01:06:01 01:08:03 122 $24.40
28:15:41 28:16:05 24 $3.85
Total amount: $28.25
aaa 01
02:00:01 04:23:59 4318 $638.80
Total amount: $638.80

分析:

这道题最坑的地方就是,如果顾客的通话时间因为拨打和挂断的时间相同导致为0,费用为0,该顾客的姓名和总费用为0是需要输出的,但是如果该顾客是因为没有任何一对匹配的拨打和挂断时间导致的费用为0,是不需要输出的。(测试点1、2、3都是因为这个原因,所以一直没有完全通过。)这题不需要考虑月份,固定都是在同一个月。

下面给出一些测试用例。

//input1
10 10 10 10 10 10 20 20 20 15 15 15 15 15 15 15 20 30 20 15 15 10 10 10
2
cyy 01:01:01:01 on-line
cyy 01:01:01:01 off-line

//output1
cyy 01
01:01:01 01:01:01 0 $0.00
Total amount: $0.00


//input2
10 10 10 10 10 10 20 20 20 15 15 15 15 15 15 15 20 30 20 15 15 10 10 10
2
cyy 01:01:01:01 on-line
cyy 01:01:01:03 on-line

//output2

//没有输出


//input3
10 10 10 10 10 10 20 20 20 15 15 15 15 15 15 15 20 30 20 15 15 10 10 10
2
cyy 01:01:01:01 off-line
cyy 01:01:01:03 on-line

//output3

//没有输出

代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <iomanip>
using namespace std;
struct Time{//时间结构体
	int month;
	int day;
	int hour;
	int minute;
};
struct record{
	string name;
	Time on[100];//记录拨打的时间
	Time off[100];//记录挂断的时间
	int da;//记录on里的个数 
	int gua;//记录off里的个数 
}r[1005];
bool compareShu(record a,record b){//姓名字典序排
	return a.name<b.name;
}
bool compareOn(Time a,Time b){//两个时间的比较
	if(a.month!=b.month){
		return a.month<b.month;
	}
	if(a.day!=b.day){
		return a.day<b.day;
	}
	if(a.hour!=b.hour){
		return a.hour<b.hour;
	}
	if(a.minute!=b.minute){
		return a.minute<b.minute;
	}
	return true;//如果时间相等返回true
}
void shuchu(Time a){
	printf("%02d:%02d:%02d",a.day,a.hour,a.minute);
}
int jisuan(Time a,Time b,int *x){//计算总价钱,从该月的第一刻开始,全部转到分钟来算
	int sum1=0;
	int sum2=0;
	int total=0;
	for(int i=0;i<24;i++){
		total+=x[i];
	}
    //如果有一整天的直接算total*天数
	sum1+=a.day*total*60;
	sum2+=b.day*total*60;
    //当天的价钱要看每一个小时的价
	for(int i=0;i<a.hour;i++){
		sum1+=x[i]*60;
	}
	sum1+=x[a.hour]*a.minute;
	for(int i=0;i<b.hour;i++){
		sum2+=x[i]*60;
	}
	sum2+=x[b.hour]*b.minute;
	return sum2-sum1;
}
int jisuanfenzhong(Time a,Time b){//计算一共的时间,全部转成分钟来算
	int sum1=0;
	int sum2=0;
	sum1=a.day*24*60+a.hour*60+a.minute;
	sum2=b.day*24*60+b.hour*60+b.minute;
	return sum2-sum1;
}
int main(){
	int a[24];
	for(int i=0;i<24;i++){
		cin>>a[i];
	}
	int n;
	cin>>n;
	int p=0;//记录人的个数
	int k;//记录电话个数
	string name; 
	Time t;//记录每一个时间
	string x;//是拨打还是结束 
	int ddd;//记录是第几个月
	for(int i=0;i<n;i++){//把数据全部存进去 
        //注意string类型不能用scanf
	    cin>>name;
		scanf("%d:%d:%d:%d",&t.month,&t.day,&t.hour,&t.minute);
		cin>>x;
		ddd=t.month;
		int j;
		bool flag=false;//判断该人是否已经存进去了 
		for(j=0;j<p;j++){
			if(r[j].name==name){//存过了
				flag=true;
				break;
			}
		}
		if(flag==false){//没存过
			j=p;
			p++;
			r[j].da=0;
			r[j].gua=0;
		}
		r[j].name=name;
		if(x=="off-line"){//现在是挂电话 
	    	r[j].off[r[j].gua]=t;
			r[j].gua++;
		}else{
			r[j].on[r[j].da]=t;
			r[j].da++;
		}
	}
	sort(r,r+p,compareShu);//先按人名的字典序排序,用于最后的输出 
	for(int i=0;i<p;i++){
		sort(r[i].on,r[i].on+r[i].da,compareOn);//将拨打时间先进行排序
		sort(r[i].off,r[i].off+r[i].gua,compareOn);//将挂断时间再进行排序
		int ci=0;//看是否需要输出人名 
		int onpoint=0,offpoint=0;
		int sum=0;
		while(onpoint<r[i].da&&offpoint<r[i].gua){
			if(compareOn(r[i].on[onpoint],r[i].off[offpoint])){
				if(onpoint!=r[i].da-1&&compareOn(r[i].on[onpoint+1],r[i].off[offpoint])){//如果此时不是最后一个,还需要考虑是不是后面的才是匹配的on,off要和时间最近的on匹配 
					onpoint++;
				}else{
					ci++;
					if(ci==1){//该人有匹配的时间对,第一次需要输出其姓名和月份
						cout<<r[i].name<<" "<<setw(2)<<setfill('0')<<ddd<<endl;
					} 
					shuchu(r[i].on[onpoint]);
					cout<<" ";
					shuchu(r[i].off[offpoint]);
					cout<<" ";
					cout<<jisuanfenzhong(r[i].on[onpoint],r[i].off[offpoint]);
					cout<<" ";
					cout<<"$"<<fixed<<setprecision(2)<<jisuan(r[i].on[onpoint],r[i].off[offpoint],a)*1.0/100<<endl;
					sum+=jisuan(r[i].on[onpoint],r[i].off[offpoint],a);
					onpoint++;
					offpoint++;
				}
			}else{
				offpoint++;
			}
		}
		if(ci!=0)
		cout<<"Total amount: $"<<fixed<<setprecision(2)<<sum*1.0/100<<endl;
	}
}

总结:

因为代码比较长,所以在写的时候要注意各种变量名有没有写错,注意细节。PAT里的题总是有很多意想不到的坑点,还是需要多多做,多总结经验。

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值