PAT (Advanced Level) Practice 1095 Cars on Campus 段错误的处理

一、概述

根据一天中不同时刻车辆的进出情况,输出某时刻校园内的车辆总数和在一天中在校园内呆的时间最长的车辆。

本题实际上是两道题的集合,与之前的电话费题目类似,都是要先找出合法配对再往下做。

小的坑很多,要注意。

二、分析

首先要明确一点,将时间全化为秒会好做很多,不然时分秒比较谁先谁后逻辑太麻烦了。另外本题对于运行时间较敏感,姥姥可能真拿了八万条数据来测试也说不好,少用cin和cout。

利用结构体储存出入记录。如下:

struct Car
{
	string plate_number;
	int time;
	int InorOut;
	int valid = 0;
}car[10010];

出入记录有合法的,有非法的,对于非法记录,视为无效。那么首先要把有效记录找出来。如果之前做过计算话费的题目,那就简单的多:首先以车牌号为第一优先,时间为第二优先将所有记录进行排序,然后从头开始遍历,找出所有的车牌号相同,且时间相邻,一进一出的记录,这两条都是合法记录,将其valid置为1,这样完成了数据清洗工作。与此同时还可以求出各辆车在学校呆的总时间。如下:

cmp函数

bool cmpcar(Car a, Car b)
{
	int s = a.plate_number.compare(b.plate_number);
	if (s != 0)
		return s < 0;
	else
		return a.time < b.time;
}

数据清洗

sort(car, car + N, cmpcar);
	int sumtime = 0;
	for (i = 0; i < N; i++)
	{
		if (car[i].plate_number.compare(car[i + 1].plate_number) == 0)
		{
			if (car[i].InorOut == 1 && car[i + 1].InorOut == 0)
			{
				sumtime = sumtime + car[i + 1].time - car[i].time;
				car[i].valid = 1;
				car[i + 1].valid = 1;
			}
		}
		else
		{
			mp[car[i].plate_number] = sumtime;
			sumtime = 0;
		}
	}

在将车辆与呆的总时间进行对应时,选择map较好,将string类型的车牌号与int类型的时间相对应,很方便,只不过map的按键递增没有用上,注意不能把时间当做键值,因为键值唯一,而车牌号可能有多个,把时间当做键值则只有一个车牌号会输出。

这里有极重要的一点:如果map是在main里面声明的,会导致测试点一和测试点二报段错误!!原因和在main里面开一个超大数组效果差不多,都是因为爆栈了,map的元素过多导致main受不了。

然后是计算某个时间点之前的车辆数量。注意到题目中有说明,测试时间点是递增的,这句话很重要,不会无缘无故加一条条件的,这点说明,我们不必每次都从00:00:00开始遍历相加,而是可以从上一个测试点开始往下加,节约无数时间。如下:

sort(car, car + N, cmptime);
	int k = 0;
	int carnum = 0;//这个写在里面会导致超时
	for (i = 0; i < K; i++)
	{
		int H, M, S;
		scanf("%d:%d:%d", &H, &M, &S);
		int Time = H * 3600 + M * 60 + S;
		while (car[k].time <= Time)
		{
			if (car[k].valid == 1)
			{
				if (car[k].InorOut == 1)
					carnum++;
				else
					carnum--;
			}
			k++;
		}
		printf("%d\n", carnum);
	}

然后输出即可。

三、总结

本题关键之处便在于利用好测试时间点的递增特性。

总结一下遇到的导致PAT段错误的原因吧:

main里面开大数组:简而言之就是在main里面声明了一个很大,或者可以不断递增的数组。很可能会段错误。

数组下标溢出:常出现于四万个元素刚好开个四万的数组,不妨开个五万的留有余量。

cmp函数:用>=代替>据说会导致段错误,但我还没遇到。

指针异常:这个就更少了,很少单独控制指针,太容易晕了。

PS:代码如下:

#include<stdio.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>

using namespace std;

struct Car
{
	string plate_number;
	int time;
	int InorOut;
	int valid = 0;
}car[10010];
map<string, int> mp;
map<string, int>::iterator it;
bool cmpcar(Car a, Car b)
{
	int s = a.plate_number.compare(b.plate_number);
	if (s != 0)
		return s < 0;
	else
		return a.time < b.time;
}

bool cmptime(Car a, Car b)
{
	return a.time < b.time;
}

int main()
{
	int N, K;
	scanf("%d %d", &N, &K);
	int i;
	for (i = 0; i < N; i++)
	{
		cin >> car[i].plate_number;
		int hh, mm, ss;
		scanf("%d:%d:%d", &hh, &mm, &ss);
		car[i].time = hh * 3600 + mm * 60 + ss;
		string ioo;
		cin >> ioo;
		if (ioo.compare("in") == 0)
			car[i].InorOut = 1;
		else
			car[i].InorOut = 0;
	}
	car[i].plate_number = "-1";
	car[i].time = 0;
	sort(car, car + N, cmpcar);
	int sumtime = 0;
	for (i = 0; i < N; i++)
	{
		if (car[i].plate_number.compare(car[i + 1].plate_number) == 0)
		{
			if (car[i].InorOut == 1 && car[i + 1].InorOut == 0)
			{
				sumtime = sumtime + car[i + 1].time - car[i].time;
				car[i].valid = 1;
				car[i + 1].valid = 1;
			}
		}
		else
		{
			mp[car[i].plate_number] = sumtime;
			sumtime = 0;
		}
	}

	/
	sort(car, car + N, cmptime);
	int k = 0;
	int carnum = 0;//这个写在里面会导致超时
	for (i = 0; i < K; i++)
	{
		int H, M, S;
		scanf("%d:%d:%d", &H, &M, &S);
		int Time = H * 3600 + M * 60 + S;
		while (car[k].time <= Time)
		{
			if (car[k].valid == 1)
			{
				if (car[k].InorOut == 1)
					carnum++;
				else
					carnum--;
			}
			k++;
		}
		printf("%d\n", carnum);
	}
	
	int maxnum = 0;
	int max = 0;
	for (it = mp.begin(); it != mp.end(); it++)
	{
		if (it->second > max)
			max = it->second;
	}
	for (it = mp.begin(); it != mp.end(); it++)
	{
		if (it->second == max)
			cout << it->first << " ";
	}
	printf("%02d:%02d:%02d", max / 3600, max % 3600 / 60, max % 60);
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值