试题请参见: http://pat.zju.edu.cn/contests/pat-a-practise/1016
题目概述
系统会记录每个客户的通话情况, 会告诉你每个时间段(00:00~01:00, 01:00~02:00, ...)的通话费用. 要求计算出每个客户的月账单情况.
输入
每个输入包含测试用例, 每个测试用例包含两部分: 每个时间段的通话费用(分(cent)/分钟)和每个客户的通话情况.
通话费用由24个非负整数组成, 代表了24小时内每个小时的通话费用.
接下来N(<= 1000)行是客户的通话记录. 每条记录由以下项目组成: 客户的姓名, 时间和日期(格式为month:day:hour:minute)和在线情况("on-line" 或者 "off-line")
对于每一个测试用例, 都是在同一个月内的记录. 按时间排序后, 所有"on-line"的记录之后都会跟着一条"off-line"的记录. 任何"on-line"记录之后没有"off-line"与之匹配的记录都可以被忽略; 同样地, 任何"off-line"记录之前没有"on-line"记录的记录也可以被忽略. 测试数据保证至少有一条"on-line"和"off-line"匹配的记录, 并且没有一个客户在同一时间和其他两个客户通话. 时间是24小时制的.
输出
对于每一个测试用例, 你需要打印每个客户的月账单情况.
客户按照字母顺序表排列, 对于每个客户, 你需要打印如下内容:
第1行: 客户姓名 账单对应月份
第2行起: 用户每个通话的起始和结束时间, 以及该次通话的费用
最后1行: 通话的总费用
解题思路
由于通话记录是无序的, 因此我们对每个客户用一个vector保存当前通话情况(on-line和off-line)的时间; 当全部输入结束后, 对vector进行排序.
对于每个客户的通话记录做匹配, 求出每段对话的通话时间和费用, 存储在另一个vector中.
为了方便索引, 将用户的姓名和通话情况保存在map中, 其中用户姓名作为主键.
在编码过程中, 计算每次通话的的金额是个复杂的地方.
遇到的问题
源代码
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
const int NUMBER_OF_HOURS = 24;
struct Record {
std::string time;
bool isOnline;
};
struct Call {
std::string startTime;
std::string endTime;
int totalTime;
int amount;
};
struct Customer {
std::vector<Record> records;
std::vector<Call> callRecords;
int totalAmount;
};
int atoi(char digit0, char digit1) {
return (digit0 - '0') * 10 + (digit1 - '0');
}
int getTotalTime(std::string time) {
int day = atoi(time[3], time[4]);
int hour = atoi(time[6], time[7]);
int minute = atoi(time[9], time[10]);
return day * 24 * 60 + hour * 60 + minute;
}
int getTotalMinute(const std::string& startTime, const std::string& endTime) {
return getTotalTime(endTime) - getTotalTime(startTime);
}
int getCallAmount(int* toll, const std::string& startTime, const std::string& endTime) {
int startDay = atoi(startTime[3], startTime[4]);
int endDay = atoi(endTime[3], endTime[4]);
int startHour = atoi(startTime[6], startTime[7]);
int endHour = atoi(endTime[6], endTime[7]);
int startMinute = atoi(startTime[9], startTime[10]);
int endMinute = atoi(endTime[9], endTime[10]);
int callAmount = 0;
for ( int i = startDay; i <= endDay; ++ i ) {
int lowerBound = 0, upperBound = 23;
if ( i == startDay ) {
lowerBound = startHour;
}
if ( i == endDay ) {
upperBound = endHour;
}
for ( int j = lowerBound; j <= upperBound; ++ j ) {
callAmount += toll[j] * 60;
}
}
callAmount -= toll[startHour] * startMinute + toll[endHour] * (60 - endMinute);
return callAmount;
}
int getTotalAmount(const std::vector<Call>& callRecords) {
int totalAmount = 0;
for ( size_t i = 0; i < callRecords.size(); ++ i ) {
totalAmount += callRecords[i].amount;
}
return totalAmount;
}
void getCallRecords(int* toll, Customer& customer) {
std::string previousTime;
bool previousIsOnline = false;
for ( size_t i = 0; i < customer.records.size(); ++ i ) {
if ( !customer.records[i].isOnline && previousIsOnline ) {
Call call;
call.startTime = previousTime;
call.endTime = customer.records[i].time;
call.totalTime = getTotalMinute(call.startTime, call.endTime);
call.amount = getCallAmount(toll, call.startTime, call.endTime);
customer.callRecords.push_back(call);
previousIsOnline = false;
} else if ( customer.records[i].isOnline ) {
previousTime = customer.records[i].time;
previousIsOnline = true;
}
}
customer.totalAmount = getTotalAmount(customer.callRecords);
}
bool compareRecords(const Record& record1, const Record& record2) {
return record1.time < record2.time;
}
int main() {
using std::cin;
// std::ifstream cin;
// cin.open("input.txt");
int toll[NUMBER_OF_HOURS] = {0};
int n = 0;
std::map<std::string, Customer> customers;
// Input
for ( int i = 0; i < NUMBER_OF_HOURS; ++ i ) {
cin >> toll[i];
}
cin >> n;
for ( int i = 0; i < n; ++ i ) {
std::string name, time, isOnline;
cin >> name >> time >> isOnline;
Record record;
record.time = time;
record.isOnline = ( isOnline == "on-line" );
customers[name].records.push_back(record);
}
// Process
for ( auto itr = customers.begin(); itr != customers.end(); ++ itr ) {
std::sort(itr->second.records.begin(), itr->second.records.end(), compareRecords);
getCallRecords(toll, itr->second);
}
std::string currentMonth;
for ( auto itr = customers.begin(); itr != customers.end(); ++ itr ) {
if ( itr->second.callRecords.size() != 0 ) {
currentMonth = itr->second.callRecords[0].startTime.substr(0, 2);
break;
}
}
//Output
for ( auto itr = customers.begin(); itr != customers.end(); ++ itr ) {
if ( itr->second.callRecords.size() != 0 ) {
std::cout << itr->first << " " << currentMonth << std::endl;
for ( size_t i = 0; i < itr->second.callRecords.size(); ++ i ) {
std::cout << itr->second.callRecords[i].startTime.substr(3, 8) << " " << itr->second.callRecords[i].endTime.substr(3, 8) << " "
<< itr->second.callRecords[i].totalTime << " $"
<< std::fixed << std::setprecision(2) << (itr->second.callRecords[i].amount / 100.0)
<< std::endl;
}
std::cout << "Total amount: $" << std::fixed << std::setprecision(2) <<
(itr->second.totalAmount / 100.0) << std::endl;
}
}
return 0;
}