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

1016 Phone Bills

题目描述

A long-distance telephone company charges its customers by the following rules:

Making a long-distance call costs a certain amount per minute, depending on the time of day when the call is made. When a customer starts connecting a long-distance call, the time will be recorded, and so will be the time when the customer hangs up the phone. Every calendar month, a bill is sent to the customer for each minute called (at a rate determined by the time of day). Your job is to prepare the bills for each month, given a set of phone call records.

Input Specification:

Each input file contains one test case. Each case has two parts: the rate structure, and the phone call records.

The rate structure consists of a line with 24 non-negative integers denoting the toll (cents/minute) from 00:00 - 01:00, the toll from 01:00 - 02:00, and so on for each hour in the day.

The next line contains a positive number N (≤1000), followed by N lines of records. Each phone call record consists of the name of the customer (string of up to 20 characters without space), the time and date (mm:dd:hh:mm), and the word on-line or off-line.

For each test case, all dates will be within a single month. Each on-line record is paired with the chronologically next record for the same customer provided it is an off-line record. Any on-line records that are not paired with an off-line record are ignored, as are off-line records not paired with an on-line record. It is guaranteed that at least one call is well paired in the input. You may assume that no two records for the same customer have the same time. Times are recorded using a 24-hour clock.

Output Specification:

For each test case, you must print a phone bill for each customer.

Bills must be printed in alphabetical order of customers’ names. For each customer, first print in a line the name of the customer and the month of the bill in the format shown by the sample. Then for each time period of a call, print in one line the beginning and ending time and date (dd:hh:mm), the lasting time (in minute) and the charge of the call. The calls must be listed in chronological order. Finally, print the total charge for the month in the format shown by the sample.

Sample Input:

10 10 10 10 10 10 20 20 20 15 15 15 15 15 15 15 20 30 20 15 15 10 10 10
10
CYLL 01:01:06:01 on-line
CYLL 01:28:16:05 off-line
CYJJ 01:01:07:00 off-line
CYLL 01:01:08:03 off-line
CYJJ 01:01:05:59 on-line
aaa 01:01:01:03 on-line
aaa 01:02:00:01 on-line
CYLL 01:28:15:41 on-line
aaa 01:05:02:24 on-line
aaa 01:04:23:59 off-line

Sample Output:

CYJJ 01
01:05:59 01:07:00 61 $12.10
Total amount: $12.10
CYLL 01
01:06:01 01:08:03 122 $24.40
28:15:41 28:16:05 24 $3.85
Total amount: $28.25
aaa 01
02:00:01 04:23:59 4318 $638.80
Total amount: $638.80

首先本题有几个英文单词要记录:

  • cent:美分
  • chronologically:按时间顺序

思路:

本题是PAT考试中比较恶心的一类题型,类似数据库操作,排序查找。对于本题,有几点需要注意:

  • 题目没有说一名客户一定会有on-line与off-line匹配,是说所有的客户中一定会有至少一个匹配,因此,对于没有没有匹配的客户,我们不需要输出他的任何信息(这是第二个与第三个测试用例)
  • 计算费用的时候,费率是美分为单位,最后输出要以美元为单位,注意要除以100
  • 计算费用的时候,使用模拟时间的方法来计算不同时间段的费用,累计即可。(尽量不要比较day,hour,minute等大小,按照大小分类不同计算,容易出错)

具体如下:
对于计算从d1:h1:m1到d2:h2:m2的费用,可以用下面方法

	int cost=0;
	int d = d1, h = h1, m = m1;//定义初始时间从d1:h1:m1开始
	bool flag = true;//标记有没有到达结束时间
	for (; d <= d2; d++)
	{
		for (; h <= 23; h++)
		{
			for (; m <= 59; m++)
			{
				if (d == d2 && h == h2 && m == m2)//到达结束时间,将标记改为false
				{
					flag = false;
					break;
				}
				cost+= Rate[h];//Rate是存放不同时间费率的数组,每过1分钟,增加费用
			}
			m = 0;//每过60分钟,m归零
			if (!flag)break;
		}
		h = 0;//每过24小时,h归零
		if (!flag)break;
	}

其次就是对输入数据的存储,在此我使用了这样的数据结构来存储

struct Call_Info//记录一个通话状态
{
	string time;//通话时间
	string flag;//通话状态
};

map> Store;//储存所有人的信息

使用map>的好处是map会自动根据人名的string按照字典序进行排序,之后将每一个人的通话信息存在一个结构体数组中,对这个人的通话信息进行排序的规则是按照通话的时间先后顺序:

bool compare(Call_Info a, Call_Info b)
{
	return a.time < b.time;
}

关键点就是这些,之后就是源代码供参考了

代码

//1016 Phone Bills
#include
#include
#include
#include
#include
#include

using namespace std;

inline int S2D(string a)//将两位的字符串转化为数字
{
	return (a[0] - '0') * 10 + (a[1] - '0');
}

int Rate[24];//记录不同时段的费用比率

struct Call_Info//记录一个通话状态
{
	string time;//通话时间
	string flag;//通话状态
};

map<string, vector<Call_Info>> Store;//储存所有人的信息
double res[2];//临时储存一次计算的结果
void input();//输入所有人的信息
bool compare(Call_Info a, Call_Info b);
void sort_Call_Info(vector<Call_Info>& a);
void cal_time(string time1, string time2);//通过两个时间来计算一个人该时间的通话时长与花费
void process();

int main()
{
	input();
	process();
	return 0;
}

void input()
{
	for (int i = 0; i < 24; i++)
		scanf("%d", &Rate[i]);
	int N;
	scanf("%d", &N);
	for (int i = 0; i < N; i++)
	{
		string name;
		Call_Info temp;
		cin >> name >> temp.time >> temp.flag;
		//scanf("%s %s %s",name,temp.time,temp.flag);
		Store[name].push_back(temp);
	}
	for (auto i = Store.begin(); i != Store.end(); i++)//输入后按照时间进行排序
		sort_Call_Info(i->second);
	return;
}

bool compare(Call_Info a, Call_Info b)
{
	return a.time < b.time;
}

void sort_Call_Info(vector<Call_Info>& a)
{
	sort(a.begin(), a.end(), compare);
	return;
}

void cal_time(string time1, string time2)//根据两个时间来计算通话时间与通话费用
{
	res[0] = 0; res[1] = 0;//储存结果的数组,0存历经时间,1存花费
	int ts[3], te[3];//记录开始的时间与结束的时间
	for (int i = 0, s = 3; i < 3; i++, s += 3)//将time1,time2的时间记录在两个数组中
	{
		ts[i] = S2D(time1.substr(s, 2));
		te[i] = S2D(time2.substr(s, 2));
	}
	res[0] = (te[0] - ts[0]) * 24 * 60 + (te[1] - ts[1]) * 60 + (te[2] - ts[2]);
	int d = ts[0], h = ts[1], m = ts[2];
	bool flag = true;
	for (; d <= te[0]; d++)
	{
		for (; h <= 23; h++)
		{
			for (; m <= 59; m++)
			{
				if (d == te[0] && h == te[1] && m == te[2])
				{
					flag = false;
					break;
				}
				res[1] += Rate[h];
			}
			m = 0;
			if (!flag)break;
		}
		h = 0;
		if (!flag)break;
	}
	res[1] /= 100;
	return;
}

void process()
{
	for (auto i = Store.begin(); i != Store.end(); i++)//i是不同的客户
	{
		bool flag = false;//保证有客户才输出名字,且仅输出一次,设置标记
		double sum = 0;
		for (int j = 0; j < i->second.size(); j++)
		{
			if (i->second[j].flag == "on-line" && j + 1 < i->second.size())
			{
				if (i->second[j + 1].flag == "off-line")
				{
					if(!flag)//第一次才输出客户名字
						cout << i->first << " " << i->second[0].time.substr(0, 2) << endl;
					cout << i->second[j].time.substr(3, 8) << " " << i->second[j + 1].time.substr(3, 8) << " ";
					cal_time(i->second[j].time, i->second[j + 1].time);
					printf("%d $%.2f\n", int(res[0]), res[1]);
					sum += res[1];
					flag = true;
				}
			}
		}
		if(flag)
			printf("Total amount: $%.2f\n", sum);
	}
}

git仓库:Phone Bills

你可能感兴趣的:(PAT考试)