📜  门|门 IT 2007 |第 63 题(1)

📅  最后修改于: 2023-12-03 15:12:46.732000             🧑  作者: Mango

门|门 IT 2007 | 第 63 题

这是一道关于算法的题目,在门|门IT 2007比赛中出现过。

题目描述

给定$N$个点的二维坐标$(x, y)$,请你计算出这些点中距离最近的两个点之间的距离。

输入格式

第一行包含一个整数$N$,表示点的数量。

接下来$N$行,每行包含两个整数$x$和$y$,表示一个点的二维坐标$(x, y)$。

输出格式

输出一个实数,表示两个最近点之间的距离。

样例输入
4
0 0
0 1
1 0
1 1
样例输出
1.0000000
解题思路

这道题的解题思路是比较经典的“分治算法”。

具体地,我们可以将所有的点按照横坐标从小到大排序,并且将所有横坐标与中间横坐标的距离小于等于最小距离的点加入集合$S$。

然后我们递归地处理左右两部分,取左右两部分的最小距离$d_l$和$d_r$,然后取$d=\min(d_l,d_r)$。

接下来,我们只需要考虑“跨越中间”这种情况即可。具体地,我们可以计算出距离中线距离小于$d$的点对,然后取其中最小的距离即可。

这样,我们就可以找到所有点对中的最近点对了。

代码示例

以下是基于Python实现的代码示例:

import math

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

def dist(p1, p2):
    dx = p1.x - p2.x
    dy = p1.y - p2.y
    return math.sqrt(dx * dx + dy * dy)

def closest(points):
    n = len(points)
    if n <= 1:
        return float('inf')
    elif n == 2:
        return dist(points[0], points[1])
    else:
        points.sort(key=lambda p: p.x)
        middle = n // 2
        left = points[:middle]
        right = points[middle:]
        dl = closest(left)
        dr = closest(right)
        d = min(dl, dr)
        border = points[middle - 1].x
        strip = [p for p in points if abs(p.x - border) < d]
        strip.sort(key=lambda p: p.y)
        dmin = d
        for i in range(len(strip)):
            for j in range(i + 1, len(strip)):
                if strip[j].y - strip[i].y >= dmin:
                    break
                dmin = min(dmin, dist(strip[i], strip[j]))
        return dmin

n = int(input().strip())
points = []
for i in range(n):
    x, y = map(int, input().split())
    points.append(Point(x, y))

print('%.7f' % closest(points))

closest函数实现了我们刚刚描述的分治算法,dist函数计算两个点之间的距离,而Point类表示一个二维坐标点。最后,我们只需要读入输入,调用closest函数,然后输出结果即可。

代码中的一些注释和解释可以帮助理解具体的实现方式。