1016.Phone Bills 电话费

 

题意:

第一行 给出24h中每个小时区间内的资费(分钟为单位)!!!注意时间格式是(月 日 时 分),并给出N个通话记录点,每个通话记录点都记录了姓名、当前时刻(月;日;时;分)以及其属于通话开始(on-line)或是通话结束(off-line)。现在对每个人的有效通话记录进行资费计算,有效通话记录是指同一个用户能够配对的所有on-line 和off-line,而这样的配对需满足:在按时间排序后,两条配对的on-line和off-line对应时间内不能出现其他的on-line和off-line记录。

输出要求:按姓名的字典序从小到大的顺序输出存在有效通话记录的用户,对单个用户来说,要输出他的姓名、账单月份(保证单个用户的所有记录都在同一个月产生)以及有效通话记录的时长和花费,最后输出他的总资费。资费的输出要进行转换,即把cent转换为dollar,所以结果要除以100。

样例解释:

总共三个用户 按字典序从小到大是CYJJ、CYLL、aaa(小写字母字典序大A65 a97),各自的情况

CYJJ: 只有一对匹配的记录,恰好可以配对,010559-010700 时长为61min,花费为(10*1+60*20)/100.0=12.10

CYLL:有两对匹配的记录,01 0601-01 0803  28 1605-28 1541时长分别为122min,24min。

花费计算:

第一个 八点到八点三分 3*20 六点零一到八点是(59+60)*20 一共是 2440,再除以100是24.40

第二个 十五点四十一分到十六点 (19*15+   十六点到十六点零五5*20)/100 = 3.85

aaa: 题目描述: 每一个记录都会与客户就是时间轴上的下一个记录匹配,没有匹配上的就删掉,所以010103下一个时间是020001 但这两个时间同为online,不能匹配,所以删掉010103.然后020001开始匹配 然后匹配到了下一个042359,

 

计算 02号00:00到05号00:00恰好是三天(60*6*10+60*3*20+60*7*15+60*2*20+60*30+60*15*2+60*10*3)/100  *3 再减去两个一分钟 2*1*10 得到结果为638.80

 

思路:

1 对所有记录排序   2 对每个用户判断是否存在有效的通话记录。  3 有则输出有效通话记录并计算资费。

 

具体:

一 定义结构体Record 存放单条记录的用户名 月 日 时 分 以及通话状态(online offline )

数据预处理(就是先把记录排好序)  根据题目要求写bmp函数,要求如下:

1 如果用户名不同 按字典序从小到大(大写字母字典序小)排序。

2 否则(用户名相同) 月份不同 按月份从小到大排序

3 else if 天数不同 按天数从小到大排序

4 esle if 小时不同 按小时从小到大排序

5 else 分钟不同 按分钟从小到大排序

 

二 找寻每个记录的有效通话时间: 必须保证online和offline先后出现。

!!!!!!!方法如下!!!!!!!!!!!!

设置int型变量 needPrint 表示是否存在有效通话记录,初值为0,遍历该用户的所有记录。如果在needPrint为0的情况下遇到online的记录 needPrint就为1,如果needPrintf为1的情况下,遇到offline,就置为2。 这样遍历结束之后 如果为2的话,说明用户存在有效通话记录,同时设置int型变量next,表示下一个用户的首记录在数组中的下标,并在遍历过程中对其进行累加,这样当遍历结束时,就得到next作为下一个用户的标识。

三 输出所有有效通话记录,条件:online的数组下标和offline的数组下标只相差1时才配对,反复寻找当前下标i与其下一个元素的下标i+1满足前者online 而后者offline即可。 找到即输出。

四 费用的计算方法 对已知的起始时间和终止时间,只需要不断将起始时间加1 判断其是否加到终点。

也可以把时间转换为分 再做差。

 

 

注意点:

1 配对必须保证online和offline是时间上相邻的两条记录。

2 题目保证整个输入至少有一对有效通话记录,但不保证每个用户都有。因此没有的不输出。

3 题目保证了单组数据中的月份相同。

4 边界数据

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
int rate[25];
struct record{
	char name[25];
	int yy,dd,hh,mm;
	bool status;//true online
	 
}re[1010],temp;

bool cmp(record a,record b){
	int s = strcmp(a.name,b.name);
	if(s!=0) return s<0;
	else if(a.yy!=b.yy) return a.yy<b.yy;
	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=re[on];
	while(temp.dd<re[off].dd||temp.hh<re[off].hh||temp.mm<re[off].mm){
		time++;//min
		money+=rate[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",&rate[i]);
	}
	int n;
	scanf("%d",&n);
	char line[10];
	for(int i=0;i<n;i++){
			scanf("%s ",re[i].name);
		scanf("%d:%d:%d:%d",&re[i].yy,&re[i].dd,&re[i].hh,&re[i].mm);
		scanf("%s",line);
		if(strcmp(line,"on-line")==0) re[i].status =true;
		else re[i].status =false;
	}
	sort(re,re+n,cmp);
	int on=0,off,next;
	while(on<n){
		int needprintf = 0;
		next=on;
		while(next<n&&strcmp(re[next].name,re[on].name)==0){//一个用户 
			if(needprintf==0&&re[next].status==true){
				needprintf=1;
			}else if(needprintf==1&&re[next].status==false){
				needprintf=2;
			}
			next++;
				}
		if(needprintf<2){//如果遍历完这一个用户后,没有匹配的,即needprintf不是2,则继续下一个用户 
				on =next;
				continue; //执行下一个轮回,即不打印这个用户,判断下一个! 
			}
		int Allmoney =0;
		printf("%s %02d\n",re[on].name,re[on].yy);
		while(on<next){//未到边界且不满足条件就继续找下一个 
			while(on<next-1&&!(re[on].status==true&&re[on+1].status==false)){
				on++;
			}//此事不满足while条件的on 就是需要的on值 
			off = on+1;
			 if(off==next){
			 	on =next;//如果查询完这个用户的所有记录,on值为最后一条记录,再加一就是下一条记录的开始 
			 	break;//打印完这个用户的跳出找寻的循环,先打印总金额,再进入判断是否打印-找打印-打印的循环 
			 }
		printf("%02d:%02d:%02d ",re[on].dd,re[on].hh,re[on].mm);
		printf("%02d:%02d:%02d ",re[off].dd,re[off].hh,re[off].mm);
		int time=0,money=0;
		get_ans(on,off,time,money);//这个money只是一次匹配成功的前
		Allmoney+=money;
		printf("%d $%.2f\n",time,money/100.0); 
		on=off+1;//打印完一个配对,从off+1开始再找 	
		}
		printf("Total amount: $%.2f\n",Allmoney/100.0); 
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值