PAT (Advanced Level) Practice 1046 Shortest Distance

一、概述

给出前后相连N个点,求出其中某两个点的最短距离。

给的输入是相邻两点的最短距离。

本题的难点在于当数量级特别大的时候,暴力算法很容易超时,应该说不是很容易,而是肯定会超时。这如果是在考场上,那这部分的分数就得扔了,一般这种超时bug都需整个算法推倒重来,时间代价很大。以我的暴力算法为例。

二、分析

首先说明我的暴力算法,对于前两个检查点是有效的,第三个给出超时报错。

由于模型是一个首尾相连的圆,因此两点距离有两个值。取较短的那个。注意到这两个距离相加的和是不变的,等于总距离sum,可以看做是圆的周长。因此可以选择在输入两点距离的时候直接把sum算出来。这是解决超时问题的第一步。这一步我想到了,但是没有想到这与超时问题有关,我单纯是不喜欢判断到尾巴的时候再回去加头部这一步而已。而这一步对于减少时间复杂度的帮助也微乎其微。代码如下:

int main()
{
	long N;
	scanf("%ld", &N);
	long D[100000] = { 0 };
	long i;
	long sum = 0;
	long m;
	for (i = 0; i < N; i++)
	{
		scanf("%ld", &m);
		D[i] = m;
		sum += m;
	}
	int M;
	scanf("%d", &M);
	for (i = 0; i < M; i++)
	{
		if (i != 0)
			printf("\n");
		long head, end;
		scanf("%ld %ld", &head, &end);
		long s;
		long distance = 0;;
		if (head < end)
		{
			for (s = head - 1; s < end - 1; s++)
				distance += D[s];
			if (distance <= sum / 2)
				printf("%ld", distance);
			else
				printf("%ld", sum - distance);
		}
		else if (head > end)
		{
			for(s=end - 1;s<head - 1;s++)
				distance += D[s];
			if (distance <= sum / 2)
				printf("%ld", distance);
			else
				printf("%ld", sum - distance);
		}
		else
			printf("0");
	}
}

注意到第三个检查点超时,超时的结果如图:

可以看到时间直接是0,耗费空间也是0,这对于我们debug没有帮助,我选择将输入M及之后的代码注释掉,发现结果变化如图:

看第三个检查点,发现不再是0了。可以推断,我的代码所需时间极大,全跑完不知猴年马月,因此根本就不跑直接报错。也可以看出问题就出现在了计算最短距离的地方。观察题干可知,M最大可以达到10^4,这样看来每计算一次,相当于遍历一半距离元素,时间太长了。需要在这个上面想办法。

我们注意到,每次需要计算的都是两个点之间的元素的和,那么按照计算sum的套路,计算一下每个点到第一个点的距离和,那么任意两点的距离和不就是它们与第一个点的距离和之差吗。而且每个点到第一个点的距离和很好计算,完全可以在计算总的sum的时候顺便算出来,不过是多了一个大数组罢了。这样一来,就可以极大减少计算时间,不需要再遍历M次元素了。

三、总结

笨办法人人都会想,但一定有大问题没有解决,或者是时间复杂度过高,或者是空间复杂度过高。需要想一些更好的办法。本题具有一定的代表性。应该说,凡是需要成百上千次遍历的算法,都不可能得到满分,一般都需要进行一些提前处理,另外计算一个数组什么的。

PS:代码如下:

#include<stdio.h>

int main()
{
	long N;
	scanf("%ld", &N);
	long D[100000] = { 0 };
	long Ds[100001] = { 0 };
	long i;
	long sum = 0;
	long m;
	for (i = 0; i < N; i++)
	{
		scanf("%ld", &m);
		D[i] = m;
		sum += m;
		Ds[i+1] = sum;
	}
	int M;
	scanf("%d", &M);
	for (i = 0; i < M; i++)
	{
		if (i != 0)
			printf("\n");
		long head, end;
		scanf("%ld %ld", &head, &end);
		long s;
		long distance = 0;
		if (head < end)
		{
			distance = Ds[end-1]-Ds[head-1];
			if (distance <= sum / 2)
				printf("%ld", distance);
			else
				printf("%ld", sum - distance);
		}
		else if (head > end)
		{
			distance = Ds[head-1] - Ds[end-1];
			if (distance <= sum / 2)
				printf("%ld", distance);
			else
				printf("%ld", sum - distance);
		}
		else
			printf("0");
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值