【PAT甲级】1016 Phone Bills (25分)

解题过程的小记录,如有错误欢迎指出。

题目分析

每个小时的电话费不同,给出打电话的记录,求出每位客户的电话账单进行输出。

注意点

  1. 间隔时间的分类计算,是否跨越天数,是否跨越小时数
  2. 1美元 = 100美分

我的解题过程

思路

采用record先进行数据的读入,然后对名字和时间进行排序后,为每个客户赋值对应的记录。
对我来说,本题的困难点在于:

  1. 数组的拆分,找到对应的通话记录,我通过一开始输入后就对客户和时间进行排序来解决
  2. 算出通话时间,采用了分支分类法,显得有点繁复,最后也是这里错了一处导致有一个测试点通过不了

bug

第一次提交代码后最后一个检测点没有通过,显示段错误,推测是fees[]数组相关语句的错误导致,经过检查,发现没有考虑到同一小时开始结束的情况,加入分支后得以解决

代码

#include<iostream>
#include<vector>
#include<algorithm>
#include<string>

using namespace std;

int fees[25];

struct record {
	string name;
	string time;
	string condition;
	int flag = 1;//如果为0就说明此条记录已经使用过,可以跳过
};

struct call {
	string online;
	string offline;
	int fee;
};

struct person {
	string name;
	vector<call> calls;
};

int compare1(const record r1, const record r2) {
	if (r1.name != r2.name)
		return r1.name < r2.name;
	else if (r1.time != r2.time)
		return r1.time < r2.time;
	else return 0;
}

double calculate(string online, string offline) {
	cout << online << " " << offline;
	int start_d = stoi(online.substr(0, 2));
	int end_d = stoi(offline.substr(0, 2));
	int start_h = stoi(online.substr(3, 2));
	int end_h = stoi(offline.substr(3, 2));
	int start_m = stoi(online.substr(6));
	int end_m = stoi(offline.substr(6));
	int totalmin = 0;
	double result = 0;
	if (start_h == end_h&&start_d == end_d) {//易错点:同个小时就不可以直接拿整个小时减去开始的分钟数
		totalmin += end_m - start_m;
		result = totalmin*fees[start_h];
	}
	else {
		totalmin += 60 - start_m;
		result += (60 - start_m)*fees[start_h];
		start_h++;
		if (start_h == 24) {
			start_d++;
			start_h = 0;
		}
		if (start_d == end_d) {
			while (start_h != end_h) {
				totalmin += 60;
				result += 60 * fees[start_h];
				start_h++;
			}
			totalmin += end_m;
			result += end_m*fees[end_h];
		}
		else {
			while (start_d != end_d) {
				while (start_h != 24) {
					totalmin += 60;
					result += 60 * fees[start_h];
					start_h++;
				}
				start_d++;
				start_h = 0;
			}
			while (start_h != end_h) {
				totalmin += 60;
				result += 60 * fees[start_h];
				start_h++;
			}
			totalmin += end_m;
			result += end_m*fees[end_h];
		}
	}
	printf(" %d $%.2lf\n", totalmin, result / 100.0);
	return result / 100.0;
}

int main()
{
	for (int i = 0; i < 24; i++) {
		cin >> fees[i];
	}
	int N;
	cin >> N;
	vector<record> records;
	vector<person> people;
	for (int i = 0; i < N; i++) {
		record r;
		cin >> r.name >> r.time >> r.condition;
		records.push_back(r);
	}
	sort(records.begin(), records.end(), compare1);
	for (int i = 0; i < N; i++) {
		if (records[i].flag == 0 || records[i].condition == "off-line") continue;
		int j = 0;
		for (j; j < people.size(); j++) {
			if (records[i].name == people[j].name) break;
		}
		if (j == people.size()) {//此前没有此人的通话记录
			call c;
			c.online = records[i].time;
			int k = i + 1;
			for (k; k < N; k++) {
				if (records[k].flag == 0) continue;
				if (records[k].condition != "off-line") {
					k = N;
					break;
				}
				if (records[i].name == records[k].name&&records[k].condition == "off-line") {
					c.offline = records[k].time;
					break;
				}
			}
			if (k != N) {
				records[k].flag = 0;
				person p;
				p.name = records[i].name;
				p.calls.push_back(c);
				people.push_back(p);
			}
		}
		else {//是people[j]的通话记录
			call c;
			c.online = records[i].time;
			int k = i + 1;
			for (k; k < N; k++) {
				if (records[k].flag == 0) continue;
				if (records[k].condition != "off-line") {
					k = N;
					break;
				}
				if (records[i].name == records[k].name&&records[k].condition == "off-line") {
					c.offline = records[k].time;
					break;
				}
			}
			if (k != N) {
				records[k].flag = 0;
				people[j].calls.push_back(c);
			}
		}
		records[i].flag = 0;
	}
	for (int i = 0; i < people.size(); i++) {
		cout << people[i].name << " " << people[i].calls[0].online.substr(0, 2) << endl;
		double total = 0;
		for (int j = 0; j < people[i].calls.size(); j++) {
			total += calculate(people[i].calls[j].online.substr(3), people[i].calls[j].offline.substr(3));
		}
		printf("Total amount: $%.2lf\n", total);
	}
    return 0;
}


dalao的代码

全部代码因版权原因不放出来,大家可以自行去柳神博客购买或者参考晴神的上机笔记~

借鉴点

  1. 以下比较函数更为简洁
bool cmp(node a, node b) {
 	return a.name != b.name ? a.name < b.name : a.time < b.time; 
}
  1. 设置一个变量保存打一天的花费,后序计算隔天时可以直接加上,顺便学习一下数组的初始化赋值方法
int rate[25] = {0};
for (int i = 0; i < 24; i++) {
	scanf("%d", &rate[i]);
 	rate[24] += rate[i];
}
  1. 直接算出每个时间点到00:00:00的分钟数再两个进行相减
  2. 采用了map的键值对来对应每个客户的call
  3. 柳神的关于这题的代码还是有很多参考的地方,建议背诵全文(bushi)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值