[PAT-A 1016]Phone Bills

在这里插入图片描述
题目大意:
给出24h中每个小时区间内的资费,给出N个通话记录点,每个记录点记录了姓名,当前时刻:(月:日:时:分)通话开始(on-line)结束:(off-line) 对每个人的有效通话记录进行资费计算。
”有效通话记录“:可以理解为对同一个人的通话记录按照时间先后顺序排序后一对连续的on-line off-line

思路:
对所有记录进行排序,并且判断是否存在有效通话记录,如果有则输出有效通话记录,同时计算时长,统计资费

输入信息结构体定义:

struct Record {
	char name[25];
	int month, dd, hh, mm;
	bool status;//statue==ture:on-line status==false :off-line
}rec[maxn], temp;

1.排序cmp函数:
1)用户名不同,以用户名从小到大。
2) 用户名相同,以时间从小到大,即月份,日期,小时,分钟的顺序有效到大的顺序。

bool cmp(Record a, Record b) {
	int s = strcmp(a.name, b.name);
	if (s != 0)return s < 0;
	else if (a.month != b.month)return a.month < b.month;
	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;
}

2.判断是否存在有效通话记录(即是否需要输出)

int on,int next;//on表示该用户第一条记录,即开始,next表示当先下一条记录
while(on<总数){
	int needPrint=0;//needPrint=0为初值,=1为匹配到on-line =2表示需要输出
	next=on;
	while(next<总数&&姓名匹配还是当前用户){
		if(needPrint==0&&当前记录状态为on-line)needPrint=1;
		else if(needPrint==1&&当前记录状态为off-line)needPrint=2;//配对成功表示需要输出
		next++;
	}
	if(needPrint<2){//如果没有匹配到的,就继续下一个用户
		on=next;
		continue;
	}
}

3.如果needPrint==2,输出有效记录
遍历该用户列表,找见当前记录为on-line并且下一条记录为off-line的记录,对该记录进行资费统计
(资费统计)可以统计一共有多少分钟,根据每个时段的的价位累加
用来计算两个时间之间的差值的算法(常考)

//也可以推到年月日,计算天数
while(start.day < end.day || start.hour < end.hour || start.minute < end.minute){
    start.minute++;
    if(start.minute == 60){
        start.minute = 0;
        start.hour++;
    }
    if(start.hour = 24){
        start.hour = 0;
        start.day++;
    }
}

本题的版本:

void get_ans(int on, int off, int &time, int &money) {
	temp = rec[on];
	while (temp.dd < rec[off].dd || temp.hh < rec[off].hh || temp.mm < rec[off].mm) {
		time++;
		money += toll[temp.hh];
		temp.mm++;
		if (temp.mm >= 60) {
			temp.mm = 0;
			temp.hh++;
		}
		if (temp.hh >= 24) {
			temp.hh = 0;
			temp.dd++;
		}
	}
}

最后累加该用户的所有通话记录的总费用并输出。(资费单价是美分,要换算成美元)

4.进行下一个用户

AC代码:

//PAT_A 1016
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1010;
int toll[25];
struct Record {
	char name[25];
	int month, dd, hh, mm;
	bool status;
}rec[maxn], temp;
bool cmp(Record a, Record b) {
	int s = strcmp(a.name, b.name);
	if (s != 0)return s < 0;
	else if (a.month != b.month)return a.month < b.month;
	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 = rec[on];
	while (temp.dd < rec[off].dd || temp.hh < rec[off].hh || temp.mm < rec[off].mm) {
		time++;
		money += toll[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", &toll[i]);
	}
	int n;
	char line[10];
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		(void)scanf("%s", rec[i].name);
		(void)scanf("%d:%d:%d:%d", &rec[i].month, &rec[i].dd, &rec[i].hh, &rec[i].mm);
		(void)scanf("%s", line);
		if (strcmp(line, "on-line") == 0)rec[i].status = true;
		else rec[i].status = false;
	}
	sort(rec, rec + n, cmp);
	int on = 0, off, next;
	while (on < n) {//循环处理单个用户的所有记录
		int needPrint = 0;//表示该用户是否需要输出
		next = on;//从当前位置开始寻找下一个用户,next中存储的是下一个用户的首地址
		while (next < n && strcmp(rec[next].name, rec[on].name) == 0) {
			if (needPrint == 0 && rec[next].status == true)needPrint = 1;//找到on 置1
			else if (needPrint == 1 && rec[next].status == false)needPrint = 2;//on之后找到off 置2
			next++;
		}
		if (needPrint < 2) {//没有配对的on-off
			on = next;
			continue;
		}
		int AllMoney = 0;
		printf("%s %02d\n", rec[on].name, rec[on].month);
		while (on < next) {
			while (on < next - 1 && !(rec[on].status == true && rec[on + 1].status == false))on++;//找到连续的on-off
			off = on + 1;
			if (off == next) {//表示已经到了最后一个用户,开始处理下一个用户
				on = next;
				break;
			}
			printf("%02d:%02d:%02d ", rec[on].dd, rec[on].hh, rec[on].mm);
			printf("%02d:%02d:%02d ", rec[off].dd, rec[off].hh, rec[off].mm);
			int time = 0, money = 0;
			get_ans(on, off, time, money);
			AllMoney += money;
			printf("%d $%.2f\n", time, money / 100.0);
			on = off + 1;
		}
		printf("Total amount: $%.2f\n", AllMoney / 100.0);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值