「SDOI2012」最近最远点对

传送门

由于本人比较菜,所以只写了个旋转坐标系的做法 \(Q \omega Q\)

旋转坐标系的原理很显然,我们考虑到离得最近的两个点,它们的横坐标之差肯定也不会大,离得最远的同理。

但是我们肯定还是不能 naive 地直接去算,为了更好地保证正确性,我们可以随机旋转坐标系。

虽然操作不好会 T ,不过这题确实还是稳过的。

参考代码:

#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
using namespace std;

const double pi = acos(-1.0);
const int _ = 2e5 + 5;

int n; double mn = 1e18, mx = 0;
struct node { double x, y; } t[_];
int cmp(node a, node b) { return a.x < b.x; }

double dist(node a, node b) { return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); }

void calc(double d) {
    d = d / 180.0 * pi;
    for (int i = 1; i <= n; ++i) {
        double x = t[i].x, y = t[i].y;
        t[i].x = x * cos(d) - y * sin(d);
        t[i].y = x * sin(d) + y * cos(d);
    }
    sort(t + 1, t + n + 1, cmp);
    for (int i = 1; i <= n; ++i)
        for (int j = i + 1; j <= min(i + 10, n); ++j)
            mn = min(mn, dist(t[i], t[j]));
    for (int i = 1; i <= min(10, n); ++i)
        for (int j = max(1, n - 9); j <= n; ++j)
            mx = max(mx, dist(t[i], t[j]));
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("cpp.in", "r", stdin), freopen("cpp.out", "w", stdout);
#endif
    srand(time(0));
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%lf %lf", &t[i].x, &t[i].y);
    calc(0);
    calc(rand() % 360);
    calc(rand() % 360);
    printf("%.5lf %.5lf\n", mn, mx);
    return 0;
}
posted @ 2020-06-19 13:31  Sangber  阅读(275)  评论(1编辑  收藏  举报