PAT A1016 Phone Bills

题目描述

在这里插入图片描述

知识点

排序

实现

码前思考

在这里插入图片描述
2. 由于经过了按名字排序,所以相同的用户一定在一起,那么就可以进行on和off的匹配了,匹配就是一个比较easy思考的问题了,主要是代码比较复杂;

代码实现

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;
const int maxn = 1e3+10;

int rate[30];
int n;
int dayRate=0;
int month; 
struct call{
	string name;
	bool isOn;
	int dd;
	int hh;
	int mm; 
}calls[maxn];

bool cmp(call a,call b){
	if(a.name != b.name){
		return a.name < b.name;
	}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 main(){
	for(int i=0;i<24;i++){
		scanf("%d",&rate[i]);
		dayRate += rate[i];
	}
	//printf("dayRate:%d\n",dayRate);
	
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		string name;
		int dd;
		int hh;
		int mm;
		string status;
		cin>>name;
		scanf("%d:%d:%d:%d",&month,&dd,&hh,&mm);
		cin>>status;
		calls[i].name = name;
		calls[i].dd = dd;
		calls[i].hh = hh;
		calls[i].mm = mm;
		if(status == "on-line"){
			calls[i].isOn = true; 
		}else{
			calls[i].isOn = false;
		}
	}
	
	//排序
	sort(calls,calls+n,cmp);
	
//	for(int i=0;i<n;i++){
//		cout<<calls[i].name<<" "<<calls[i].dd<<" "<<calls[i].hh<<" "<<calls[i].mm<<endl;
//	} 
	
	//然后遍历每一组名字相同的,寻找匹配的时间
	int idx = 0;	//从第0个开始
	int tot = 0;
	string preName = "yc"; //表示是否是重新开始的
	
	//好坑啊 
	while(idx < n-1){	//不能是最后一个!最后一个会被提前匹配 
		//发现匹配直接进行输出了 
		int cur = 0;	//表示当前匹配call计费 
		if(calls[idx].isOn == true){
			if(calls[idx].name == calls[idx+1].name){
				if(calls[idx+1].isOn == false){
					//而且是挂线
					//计算时间
					int sdd = calls[idx].dd;
					int edd = calls[idx+1].dd;
					int shh = calls[idx].hh;
					int ehh = calls[idx+1].hh;
					int smm = calls[idx].mm;
					int emm = calls[idx+1].mm;
					int last = 0;
					if(sdd != edd){
						//那么要计算一下跳天总数 
						cur += (edd-sdd-1) * dayRate * 60;
						last += (edd-sdd-1) * 60 * 24;
						
						int scnt=0;
						int ecnt=0;
						//计算scnt
						scnt += rate[shh] * (60-smm); 
						last +=  (60-smm); 
						for(int j=shh+1;j<24;j++){
							scnt += rate[j] * 60;
							last += 60;
						}
						//计算ecnt
						for(int j=0;j<ehh;j++){
							ecnt += rate[j] * 60;
							last += 60;
						}
						ecnt += rate[ehh] * (emm); 
						last += emm; 
						//累加 
						cur += scnt;
						cur += ecnt;  
					}else{
						//在同一天
						//判断是否在同一个小时
						if(shh == ehh){
							cur += rate[shh] * (emm - smm);
							last += (emm - smm);
						}else{
							cur += rate[shh] * (60-smm);
							last += (60-smm);
							for(int j=shh+1;j<ehh;j++){
								cur += rate[j] * 60;
								last += 60;
							}
							cur += rate[ehh] * emm;
							last += emm;
						} 
					}
					//输出
					//如果之前输出过了 
					if(calls[idx].name == preName){
						//那么累加
						printf("%02d:%02d:%02d %02d:%02d:%02d %d $%.2f\n",sdd,shh,smm,edd,ehh,emm,last,1.0*cur/100);
						tot += cur;	 
					}else{
						//输出上次tot
						if(preName != "yc"){
							printf("Total amount: $%.2f\n",1.0*tot/100);
						} 
						preName = calls[idx].name;
						printf("%s %02d\n",calls[idx].name.c_str(),month);
						printf("%02d:%02d:%02d %02d:%02d:%02d %d $%.2f\n",sdd,shh,smm,edd,ehh,emm,last,1.0*cur/100);
						tot = cur;
					} 
					//两次加加,其实一次也行 
					idx++;
					idx++; 
				}else{
					//说明不是挂线
					idx++;	
				} 
			}else{
				//直接下一步
				idx++; 
			}
		}else{
			//说明是挂线,这个判断很重要 
			idx++; 
		} 
	} 
	printf("Total amount: $%.2f\n",1.0*tot/100);
	return 0;
} 

码后反思

  1. 之前将while(idx < n-1)写成了while(idx != n-1)导致测试点1段错误,好坑啊;
  2. 算法笔记上的解法非常暴力,居然是让程序一步步加分钟的!这样虽然暴力,但是确实比我这个要好写多了。。。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值