一、概述
给出前后相连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");
}
}