PAT (Advanced Level) Practice 1016 Phone Bills

一、概述

题设太复杂,简而言之收话费。

坑点主要有以下几个:

总话费为0的话什么都不输出,就当没有这个人,我觉得这个逻辑有问题,因为题设中各小时的话费是非负数,因此可能是0,说不定电信公司善心大发呢,这样即使有有效通信话费也可能是0,但是没考虑这种情况;

输出的小数位一位时要加0,因为例子给的十分好,都是10啊5啊什么的,所以对于总话费的输出容易忘了加0,或者是像我一样对100取余,这样后面的0是保留了,但是前面的0还是没加上。这样测试点123都过不去,很亏的;

既是坑点又是难点的是话费的计算,很难想,有两种方法:其一是从打电话的一刻起一分钟一分钟加,加到挂电话的时刻;其二是打电话的时刻与00:00:00计算一个话费,挂电话的时刻也一样,因为与00:00:00相减计算话费好算一点;然后这两个的话费相减。我用了前者,优化了一下,退出循环不再是与挂电话时刻相等,而是选择利用总通话分钟数,这样就避开了对于跨天通话的计算,简单了一点。

二、分析

使用结构体储存通话记录,如下:

struct Deal
{
	char name[21];
	int MM;
	int DD;
	int hh;
	int mm;
	int OnorOff;
}deal[1000];

这应该是轻车熟路。

cmp函数如下:

bool cmp(Deal a, Deal b)
{
	int s = strcmp(a.name, b.name);
	if (s != 0)
		return s < 0;
	else if (a.MM != b.MM)
		return a.MM < b.MM;
	else if (a.DD != b.DD)
		return a.DD < b.DD;
	else if (a.hh != b.hh)
		return a.hh < b.hh;
	else if (a.mm != b.mm)
		return a.mm < b.mm;
}

如果想要字典序升序输出,就应像如图所示,而不能像像下面这样

bool cmp(Deal a, Deal b)
{
	if (a.name!=b.name)
		return a.name < b.name;
	else if (a.MM != b.MM)
		return a.MM < b.MM;
	else if (a.DD != b.DD)
		return a.DD < b.DD;
	else if (a.hh != b.hh)
		return a.hh < b.hh;
	else if (a.mm != b.mm)
		return a.mm < b.mm;
}

这会报错。要使用strcmp来比较是否相等,然后用其返回值与0比较来看是升序还是降序。

主函数先是输入数据,然后是排序,这都不难,关键是计算话费:

for (i = 0; i < N-1; i++)
	{
		if (strcmp(deal[i].name, deal[i + 1].name) == 0)
		{
			if (deal[i].OnorOff == 0 && deal[i + 1].OnorOff == 1)
			{
				exist = 1;
				int premin = deal[i].DD * 1440 + deal[i].hh * 60 + deal[i].mm;
				int aftmin = deal[i + 1].DD * 1440 + deal[i + 1].hh * 60 + deal[i + 1].mm;
				int totalmin = aftmin - premin;
				int cost = 0;
				int startmm = deal[i].mm;
				int starthh = deal[i].hh;
				while (startmm != totalmin+ deal[i].mm)
				{
					startmm++;
					cost += perhour[starthh];
					if (startmm % 60 == 0)
						starthh++;
					if (starthh > 23)
						starthh = 0;
				}
				if (cost != 0)
				{
					if (name == 0)
					{
						printf("%s %02d\n", deal[i + 1].name, deal[i + 1].MM);
						name = 1;
					}
					printf("%02d:%02d:%02d %02d:%02d:%02d", deal[i].DD, deal[i].hh, deal[i].mm, deal[i + 1].DD, deal[i + 1].hh, deal[i + 1].mm);
					printf(" %d $%d.%02d\n", totalmin, cost / 100, cost % 100);//注意02d
					totalcost += cost;
				}
			}
		}
		else
		{
			name = 0;
			if(totalcost !=0)
				printf("Total amount: $%d.%02d\n", totalcost / 100, totalcost % 100);
			totalcost = 0;
			exist = 0;
		}
	}
	if (totalcost != 0)
		printf("Total amount: $%d.%02d\n", totalcost / 100, totalcost % 100);

注意,有效通话在排序之后应满足如下条件,即前后两条记录名称相同,一条是通话一条是挂断,这样才能够计算话费。计算之后如果话费非0,输出名字和话费。利用旗语name来输出且只输出一次名字和月份,利用exist来保证有可用的通话记录。

三、总结

其他地方都对,但是只有测试点一过了,话费的%02d花了我一个多小时才找出来,然后加了十分。真是心酸啊。

PS:代码如下:

#include<cstdio>
#include<string>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

struct Deal
{
	char name[21];
	int MM;
	int DD;
	int hh;
	int mm;
	int OnorOff;
}deal[1000];

int perhour[24] = { 0 };

bool cmp(Deal a, Deal b)
{
	int s = strcmp(a.name, b.name);
	if (s != 0)
		return s < 0;
	else if (a.MM != b.MM)
		return a.MM < b.MM;
	else if (a.DD != b.DD)
		return a.DD < b.DD;
	else if (a.hh != b.hh)
		return a.hh < b.hh;
	else if (a.mm != b.mm)
		return a.mm < b.mm;
}

int main()
{
	int i;
	for (i = 0; i < 24; i++)
		scanf("%d", &perhour[i]);
	int N;
	scanf("%d", &N);
	for (i = 0; i < N; i++)
	{
		scanf("%s %d:%d:%d:%d", &deal[i].name, &deal[i].MM, &deal[i].DD, &deal[i].hh, &deal[i].mm);
		string onlineoroffline;
		cin >> onlineoroffline;
		if (onlineoroffline.compare("on-line")==0)
			deal[i].OnorOff = 0;
		else
			deal[i].OnorOff = 1;
	}
	sort(deal, deal + N, cmp);
	int name = 0;
	int totalcost = 0;
	int exist = 0;
	for (i = 0; i < N-1; i++)
	{
		if (strcmp(deal[i].name, deal[i + 1].name) == 0)
		{
			if (deal[i].OnorOff == 0 && deal[i + 1].OnorOff == 1)
			{
				exist = 1;
				int premin = deal[i].DD * 1440 + deal[i].hh * 60 + deal[i].mm;
				int aftmin = deal[i + 1].DD * 1440 + deal[i + 1].hh * 60 + deal[i + 1].mm;
				int totalmin = aftmin - premin;
				int cost = 0;
				int startmm = deal[i].mm;
				int starthh = deal[i].hh;
				while (startmm != totalmin+ deal[i].mm)
				{
					startmm++;
					cost += perhour[starthh];
					if (startmm % 60 == 0)
						starthh++;
					if (starthh > 23)
						starthh = 0;
				}
				if (cost != 0)
				{
					if (name == 0)
					{
						printf("%s %02d\n", deal[i + 1].name, deal[i + 1].MM);
						name = 1;
					}
					printf("%02d:%02d:%02d %02d:%02d:%02d", deal[i].DD, deal[i].hh, deal[i].mm, deal[i + 1].DD, deal[i + 1].hh, deal[i + 1].mm);
					printf(" %d $%d.%02d\n", totalmin, cost / 100, cost % 100);
					totalcost += cost;
				}
			}
		}
		else
		{
			name = 0;
			if(totalcost !=0)
				printf("Total amount: $%d.%02d\n", totalcost / 100, totalcost % 100);
			totalcost = 0;
			exist = 0;
		}
	}
	if (totalcost != 0)
		printf("Total amount: $%d.%02d\n", totalcost / 100, totalcost % 100);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值