题意
给 nnn 个点,每个点坐标为 (xi,yi)(x_i, y_i)(xi,yi)。
要求我们其中找到两个点,使得这两个点之间的曼哈顿距离最大。
暴力求解
首先,我们想到一个暴力的算法。
LL maxx=0;
for (LL i=1; i<=n; i++) {
for (LL j=1; j<=n; j++) {
if (i==j) {
//同一个点
continue;
}
maxx = max(maxx, abs(x[i]-x[j])+abs(y[i]-y[j]);
}
}
时间复杂度
很容易知道暴力的时间复杂度为 O(N2)O(N^2)O(N2)。
由于本题的 nnn 相对比较大,达到 10510^5105 级别,因此这样的算法本题一定是 TLE。
优化算法
根据暴力的算法,我们知道需要优化部分就是 ∣xi−xj∣+∣yi−yj∣|x_i-x_j|+|y_i-y_j|∣xi−xj∣+∣yi−yj∣。
为了不失通用性,我们可以假设这两点就是 x1x_1x1 和 x2x_2x2。那么本题就变为求 ∣x1−x2∣+∣y1−y2∣|x_1-x_2|+|y_1-y_2|∣x1−x2∣+∣y1−y2∣。
我们分类讨论:
- x1>x2,y1>y2x_1>x_2, y_1> y_2x1>x2,y1>y2,变为 x1−x2+y1−y2→(x1+y1)+((−x2)+(−y2))x_1-x_2+y_1-y_2 \to (x_1+y_1)+((-x_2)+(-y_2))x1−x2+y1−y2→(x1+y1)+((−x2)+(−y2));
- x1>x2,y1<y2x_1>x_2, y_1<y_2x1>x2,y1<y2,变为 x1−x2+y2−y1→(x1−y1)+((−x2)+y2)x_1-x_2+y_2-y_1 \to (x_1-y_1)+((-x_2)+y_2)x1−x2+y2−y1→(x1−y1)+((−x2)+y2);
- x1<x2,y1>y2x_1<x_2, y_1>y_2x1<x2,y1>y2,变为 x2−x1+y1−y2→(−(x1)+y1)+(x2−y2)x_2-x_1+y_1-y_2 \to (-(x_1)+y_1)+(x_2-y_2)x2−x1+y1−y2→(−(x1)+y1)+(x2−y2);
- x1<x2,y1<y2x_1<x_2, y_1<y_2x1<x2,y1<y2,变为 x2−x1+y2−y1→((−x1)+(−y1))+(x2+y2)x_2-x_1+y_2-y_1 \to ((-x_1)+(-y_1))+(x_2+y_2)x2−x1+y2−y1→((−x1)+(−y1))+(x2+y2);
通过观察上面的结果,我们发现,需要计算如下 444 个部分:x1+y1,x1−y1,−x1+y1,−x1−y1x_1+y_1, x_1-y_1, -x_1+y_1, -x_1-y_1x1+y1,x1−y1,−x1+y1,−x1−y1 即可。
也就是说,每次将一个点,分解为 444 个点。通过分别对 444 个方向点排序,这样最小值在下标为 111 的数组,最大值在下标为 nnn 的数组中。我们只需要计算一下这 444 个方向点的最大值即为答案。
AC 参考
#include <bits/stdc++.h>
using namespace std;
using LL=long long;
const int N=1e6+10;
LL a[6][N];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
LL n;
cin>>n;
for (LL i=1; i<=n; i++) {
LL x,y;
cin>>x>>y;
a[1][i]=x+y;
a[2][i]=-x+y;
a[3][i]=x-y;
a[4][i]=-x-y;
}
for (LL i=1; i<=4; i++) {
sort(a[i]+1, a[i]+1+n);
}
LL maxx=0;
for (LL i=1; i<=4; i++) {
maxx=max(maxx, a[i][n]-a[i][1]);
}
cout<<maxx<<"\n";
return 0;
}
时间复杂度
O(nlogn)O(nlogn)O(nlogn),也就是排序占用了最多的时间。