题意
给出 个二维座标点,要求给出两个点的编号满足此两点间距离最远,仅允许走 度斜边与网格边。
思路
此题仅允许走斜边与网格边,而非最短路径,因此不同于之前仅考虑最短路径的做法,即求凸包直径。(不过此题直接求凸包直径貌似也能过,应该是因为此种新定义的路径与绝对路径间的差值不大有关)
此题求法非常巧妙,我们可以先列举下述四种情况,对整体题目有一个大致把握。
上述四种情况中,红色边为真实路径,因此我们可以列出路径的计算公式如下。
此四种情况即为本题计算答案时所有的情况,不难发现,对于情况一来说,如果采用的公式非公式 ,则 会变小,即对于每一种情况来说,只有使用其情况所对应的公式才能获得最大的 值,所以我们可以对于上述的四种情况分别计算。
以情况 为例,每次选取 的最大值和最小值,然后最大值减去最小值即为该情况下的两点距离最大值。
总结
此做法不单适应于本题,如果题目改为只能走网格边或者变成切比雪夫座标系,本做法都可以非常简单地解决。因此该做法的思想比较精妙,需要掌握!
代码
#include <bits/stdc++.h>
const int N = 2e5+100;
const double inf = 1e16;
const double E = sqrt(2)-1;
using namespace std;
double X[N], Y[N], ans, f[4][2] = {{E,1},{E,-1},{1,E},{1,-E}};
int n, p1, p2, id1, id2;
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; i++) scanf("%lf%lf",&X[i],&Y[i]);
for(int k = 0; k < 4; k++){
double maxn = -inf, minn = inf;
for(int i = 1; i <= n; i++){
double cur = X[i] * f[k][0] + Y[i] * f[k][1];
if(cur > maxn) maxn = cur, id1 = i;
if(cur < minn) minn = cur, id2 = i;
}
if(ans < maxn-minn) ans = maxn-minn, p1 = id1, p2 = id2;
}
printf("%d %d\n", p1, p2);
}
后记
博观而约取,厚积而薄发。