PAT A1016 Phone Bills (25分)

整体思路是先读入数据,再将其进行排序,最后遍历进行配对输出。几个细节:

1.结构体中

struct records {
	char name[25];
	int time[4];//month,day,hour,minute
	int state;//1 for online 0 for offline
}rec[1010];

用一个int型的state,1/0代表online和offline

2.读取数据时,用getchar吸收掉空格

3.配对

temp代表上一个记录,rec[i]代表当前记录

i)当temp.name与rec[i].name不相同时,代表开始遍历另一个人的记录了,此时输出上一个人的总费用,并重置sum,temp指向当前记录,开始下一轮循环

ii)否则是同一个人记录,检查state,只有符合temp.state==1&&rec[i].state == 0时,才代表配对成功

注意:首次配对成功,输出一个名字 和 月份

计算这对记录所产生的费用fare,累加到sum。注意:不要忘记清零fare。

temp指向当前记录,开始下一轮循环

4.在输出某人的sum时,若sum为0,代表此人没有有效配对记录

5.因为上面的逻辑,当有1个以上的人拥有有效配对记录时,最后一个人的sum将不会被输出,需要在循环外面补上。

7.费用计算pair_fare():

采用类似日期间隔计算的方式,加1遍历。参考:Codeup1928 日期差值

注意:fare最后的计算要由美分转化为美元。1美元=100美分

AC代码:

//1016 Phone Bills (25分) https://pintia.cn/problem-sets/994805342720868352/problems/994805493648703488
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct records {
	char name[25];
	int time[4];//month,day,hour,minute
	int state;//1 for online 0 for offline
}rec[1010];
bool cmp(records r1, records r2)//先排序然后再配对
{
	if (strcmp(r1.name, r2.name) != 0) return strcmp(r1.name, r2.name) < 0;
	else if (r1.time[0] != r2.time[0]) return r1.time[0] < r2.time[0];
	else if (r1.time[1] != r2.time[1]) return r1.time[1] < r2.time[1];
	else if (r1.time[2] != r2.time[2]) return r1.time[2] < r2.time[2];
	else if (r1.time[3] != r2.time[3]) return r1.time[3] < r2.time[3];
}
void pair_fare(records on, records off, double* fare, int* rate)
{
	int d1 = on.time[1];
	int h1 = on.time[2];
	int m1 = on.time[3];
	int d2 = off.time[1];
	int h2 = off.time[2];
	int m2 = off.time[3];
	int min = 0;
	while (d1 < d2 || h1 < h2 || m1 < m2)
	{
		m1++;
		*fare += rate[h1];
		min++;
		if (m1 > 59)
		{
			h1++;
			m1 = 0;
			if (h1 > 23) {
				d1++;
				h1 = 0;
			}
		}
	}
	*fare /= 100;//1美元=100美分
	printf("%02d:%02d:%02d %02d:%02d:%02d %d $%.2lf\n", on.time[1], on.time[2], on.time[3], off.time[1], off.time[2], off.time[3], min, *fare);
}
int main()
{
	int rate[24] = { 0 };
	for (int i = 0; i < 24; i++) {
		scanf("%d", rate + i);
	}
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%s %d:%d:%d:%d", rec[i].name, rec[i].time, rec[i].time + 1, rec[i].time + 2, rec[i].time + 3);
		char str[10] = { 0 };
		getchar();//吸收掉空格
		scanf("%s", str);
		if (strcmp(str, "on-line") == 0) rec[i].state = 1;
		else rec[i].state = 0;
	}
	sort(rec, rec + n, cmp);//排序
	records temp;//上一条记录
	bool change = true;
	temp = rec[0];
	double sum, fare;//每个人的总费用和每个配对的费用
	sum = fare = 0;
	for (int i = 1; i < n; i++) {
		if (strcmp(rec[i].name, temp.name) != 0) {//另外一个人开始配对
			change = true;
			if (sum)
				printf("Total amount: $%.2lf\n", sum);
			sum = 0;
			temp = rec[i];
			continue;
		}
		if (temp.state==1&&rec[i].state == 0) {//配对成功
			if (change) {//首次配对将输出名字 和 月份
				printf("%s %02d\n", temp.name, temp.time[0]);
				change = false;
			}
			pair_fare(temp, rec[i], &fare, rate);
			sum += fare;
			//fare忘记清零
			fare = 0;
		}
		temp = rec[i]; 
	}
	if (sum)
		printf("Total amount: $%.2lf", sum);
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值