PAT甲级 1046 Shortest Distance (20分) (题目 + 代码 + 详细注释 + 最后一个测试点超时分析)

The task is really simple: given N exits on a highway which forms a simple cycle, you are supposed to tell the shortest distance between any pair of exits.

Input Specification:

Each input file contains one test case. For each case, the first line contains an integer N (in [3,10_​5​​]), followed by N integer distances D​1​​ D​2​​ ⋯ D​N​​, where D​i​​ is the distance between the i-th and the (i+1)-st exits, and D​N​​ is between the N-th and the 1st exits. All the numbers in a line are separated by a space. The second line gives a positive integer M (≤10​_4​​), with M lines follow, each contains a pair of exit numbers, provided that the exits are numbered from 1 to N. It is guaranteed that the total round trip distance is no more than 10​7​​.

Output Specification:

For each test case, print your results in M lines, each contains the shortest distance between the corresponding given pair of exits.

Sample Input:

5 1 2 4 14 9
3
1 3
2 5
4 1

Sample Output:

3
10
7

//本题题意是有n个点围一个圈,求任意两点之间的最小距离,为何有最小距离呢?因为在环上从a -> b,可以顺时针,也可逆时针,所走的路程可能不一样。求法就比较简单了,可以按顺时针(逆时针也可)求出距离,和圆的周长的一半比较,若小于周长的一半,则这个距离即为所求,否则就是周长减去该距离。这是最简单的模拟,但是如果你每次得到两个点时,都一个个的把距离加起来再比较,要注意到题目中数据是n最大1e5,m最大1e4,会超时的(我就踩过坑)处理办法是在读入Di时,同时求出第(i + 1)个点到初始点(1号)的距离dis[i + 1],在求a  -> b 的距离时,只需算出 dis[b] - dis[a]即可,就是O(1)的复杂度了,不会超时了。下面是两种代码:

法一:结果超时
#include<cstdio>
#include<algorithm>
using namespace std;
int a[100005];
int main() {
	int n, sum = 0;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		sum += a[i];      //求出圆的周长
	}
	int m, k;
	k = sum / 2;         
	scanf("%d", &m);
	while (m--) {
		int x, y;
		scanf("%d%d", &x, &y);
		if (x > y)        //默认是(x, y),所以当读入的x > y时,就交换x, y
			swap(x, y);       //初用C++,原来algorithm头文件里面有swap函数,就不用自己写了
		int sum0 = 0;           //sum0是x -> y的距离,初始为0
		for (int i = x; i < y; i++)
			sum0 += a[i];
		printf("%d\n", sum0 < k ? sum0 : sum - sum0);
	}

	return 0;
}
//法二:AC了
#include<cstdio>
#include<algorithm>
using namespace std;

int a[100005], dis[100005];     //dis记录每个点到初始点(1号)的距离

int main() {
	int n, sum = 0;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		sum += a[i];
		dis[i + 1] = sum;         //因为是记录到第一个点的距离,就从第二个点开始,所以下标为 i + 1
	}
	int m, k;
	k = sum / 2;
	scanf("%d", &m);
	while (m--) {
		int x, y;
		scanf("%d%d", &x, &y);
		if (x > y)
            swap(x, y)
		int sum0 = dis[y] - dis[x];         //直接求出两点之间的距离
		printf("%d\n", sum0 < k ? sum0 : sum - sum0);
	}
		
	return 0;
}

//时隔多日,我才知道其实法二的思想是前缀和!!!

猜你喜欢

转载自blog.csdn.net/qq_45472866/article/details/104434994