跳转至

最近点对

本题我们提供了代码模板和参考 Python 实现,你可以使用模板和参考代码完成该题。

1299. Closest pair

给定 \(n\) 个二维欧几里得平面上的点 \(p_1, p_2, \dots, p_n\),请输出距离最近的两个点的距离。

限制:\(2 \leq n \leq 4\times 10^5, -10^7 \leq x_i, y_i \leq 10 ^ 7\)

Python 参考实现

这道题参考 Python 实现分治算法如下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class point:
    def __init__(self, x:int, y:int):
        self.x = x
        self.y = y
    def distance_2(self, other) -> int:
        return (self.x - other.x) ** 2 + (self.y - other.y) ** 2

def solve(a, l, r) -> int: # the square of closest distance between index range [l, r)
    if l + 1 >= r:
        return 2 ** 64 # -> INFINITY
    m = (l + r) // 2
    ret = min(solve(a, l, m), solve(a, m, r))
    strip = []
    for i in range(l, r):
        if (a[i].x - a[m].x) ** 2 < ret:
            strip.append(a[i])
    strip.sort(key=lambda p : p.y)
    for i in range(len(strip)):
        for j in range(i + 1, len(strip)):
            if (strip[i].y - strip[j].y) ** 2 >= ret:
                break
            ret = min(ret, strip[i].distance_2(strip[j]))
    return ret

n = int(input())
a = []
for i in range(n):
    x, y = map(int, input().split())
    a.append(point(x, y))
a.sort(key=lambda p : p.x)
print(solve(a, 0, n))

转译为 C++

现在,考虑使用 C++ 的 vector 来代替 Python 的 list 来实现这个算法。

整数类型区别

对于 Python 来说,整数是自带高精度扩展的,但是对于 C++ 来说并不是。这道题的数据范围要求 C++ 实现时需要 64 位整数,并且其中无穷大的值也应当小于 \(2^{64}\),因为有符号 64 位整数最大能表达 \(2 ^ {63} - 1\)

  • INF 取值要充分大,但我们推荐通常略小于类型上限的一半,因为在类似最短路、动态规划算法里存在 INF + INF 的可能性。在这份代码里,我们取到 LLONG_MAX 也是合适的,这是因为我们只用 INF 来比大小。
  • 如果你觉得 long long 打起来非常长,中间有一个空格不好看,你可以考虑使用 typedef long long LL 并在之后用 LL 指代这个类型。

更好(?)的实现

对于一般的分治算法题来说,使用一个全局数组 a 即可,不需要 vector 传为参数。

但请注意,不要在函数开始传了一个数组参数,但实际上用的全局数组的内容。这样即使能通过本题,但函数本身并没有实现期望的功能,也会对读者带来困扰。

这里给出一个代码框架,请补全代码再提交。

你当然也可以实现一个更好的代码!

你的实现不必和 Python 代码的思路一致。

你可以修改代码框架为你想要的形状,也可以从头重写。

例如,Python 代码的实现复杂度是 \(O(n \log ^ 2 n)\)。你可以优化为 \(O(n \log n)\) 的实现。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <bits/stdc++.h>
using namespace std;

const long long INF = 1e18;

/* 
   NOTE:
   std::pow is for floating point numbers.
   For integers, it's better to implement one.
*/

// FIXME: reimplement with long long int
int pow_2 (int x) {
    return x * x;
}

struct point {
    int x, y;
    point (int _x, int _y) : x(_x), y(_y) {}
    long long distance_2 (const point & other) const {
        // TODO: implement distance_2
    }
};

long long solve (vector <point> &a, int l, int r) {
    // TODO: implement solve    
}

int main() {
    int n;
    cin >> n;
    vector <point> a;
    for (int i = 0; i < n; i++) {
        int x, y;
        cin >> x >> y;
        a.push_back(point(x, y));
    }
    sort(a.begin(), a.end(), [](auto &u, auto &v) {
        return u.x < v.x;
    });
    cout << solve (a, 0, n) << endl;
}