7-10 哪两个点之间的距离最近[增强版]

设P={(x1​,y1​),(x2​,y2​),⋯,(xn​,yn​)}是平面上散列的n个点的集合。请编写程序找出集合中距离最近的点对。严格地说,相同距离的最近点对可能不止一对,为了简单期间只找出第一对最近点对即可。题目保证输入的所有数据均按照横坐标值进行升序排列。

输入格式:

输入第一行给出一个正整数n,表示平面上点的数数量。随后n行,每行给出一个实数对,每个实数对表示一个点的坐标值,其中第1数表示横坐标,第2数表示纵坐标。

输出格式:

输出最近点对中两个点的坐标和它们之间的距离。如果 x1+y1<=x2+y2则按
  (x1,y1),(x2,y2),miniDist=Distance
输出结果,否则按
  (x2,y2),(x1,y1),miniDist=Distance
输出结果。
  其中x1,y1,x2,y2是保留两位小数的实数,Distance是保留3位小数的实数

输入样例:

5
-1.00 2.00
0.00 2.00
0.50 0.60
1.00 1.00
2.00 0.00

输出样例:

(0.50,0.60),(1.00,1.00),miniDist=0.640

代码长度限制16 KB

时间限制15 ms

内存限制64 MB

答案:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define MAXN 200001

double min(double a, double b) { return a < b ? a : b; }

int n, temp[MAXN];
struct point {
    double x, y;
    friend bool operator < (point p1, point p2) {
        if (p1.x == p2.x) return p1.y < p2.y;
        return p1.x < p2.x;
    }
}p[MAXN];

bool cmp(int a, int b) {
    return p[a].y < p[b].y;
}

double getd(int x, int y) {
    return sqrt((p[x].x - p[y].x) * (p[x].x - p[y].x) + (p[x].y - p[y].y) * (p[x].y - p[y].y));
}

struct closest_pair {
    double dist;
    point p1, p2;
}cp;

closest_pair merge(int l, int r) {
    closest_pair res;
    res.dist = 2147483647.0;
    if (l == r) {
        res.p1 = p[l];
        res.p2 = p[l];
        return res;
    }
    if (l == r - 1) {
        res.dist = getd(l, r);
        if (p[l].x + p[l].y <= p[r].x + p[r].y) {
            res.p1 = p[l];
            res.p2 = p[r];
        }
        else {
            res.p1 = p[r];
            res.p2 = p[l];
        }
        return res;
    }
    int mid = (l + r) >> 1;
    closest_pair d1 = merge(l, mid);
    closest_pair d2 = merge(mid + 1, r);
    if (d1.dist < d2.dist) {
        res = d1;
    }
    else {
        res = d2;
    }
    int cnt = 0;
    for (int i = l; i <= r; ++i) {
        if (fabs(p[mid].x - p[i].x) < res.dist) {
            temp[++cnt] = i;
        }
    }
    std::sort(temp + 1, temp + cnt + 1, cmp);
    for (int i = 1; i <= cnt; ++i) {
        for (int j = i + 1; j <= cnt && p[temp[j]].y - p[temp[i]].y < res.dist; ++j) {
            double d = getd(temp[i], temp[j]);
            if (d < res.dist) {
                res.dist = d;
                if (p[temp[i]].x + p[temp[i]].y <= p[temp[j]].x + p[temp[j]].y) {
                    res.p1 = p[temp[i]];
                    res.p2 = p[temp[j]];
                }
                else {
                    res.p1 = p[temp[j]];
                    res.p2 = p[temp[i]];
                }
            }
        }
    }
    return res;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%lf %lf", &p[i].x, &p[i].y);
    }
    std::sort(p + 1, p + n + 1);
    cp = merge(1, n);
    printf("(%.2lf,%.2lf),(%.2lf,%.2lf),miniDist=%.3lf\n", cp.p1.x, cp.p1.y, cp.p2.x, cp.p2.y, cp.dist);
    return 0;
}

反馈结果:

思路: 分治

首先,定义了一个point结构体来表示一个点,包含两个属性:x和y坐标。重载了小于号运算符,以便在排序时使用。

然后,实现了一个cmp函数用于排序。这个函数根据点的y坐标进行比较,用于后面的排序操作。

接下来,实现了一个getd函数,用于计算两个点之间的距离。

然后,实现了一个merge函数,用于合并和计算最小距离。这个函数采用分治的思想,将点集分成左右两部分,分别计算左右两部分的最小距离,然后再计算两部分之间的最小距离,并返回最小值。

最后,在main函数中,读取输入的点集,对点集进行排序,然后调用merge函数计算最小距离,并输出结果。

merge函数中,对于当前的左右区间,首先计算左右区间各自的最小距离 d1和 d2,然后取其中较小的一个作为初始最小距离 d

接下来,通过遍历左边区间的点,在横坐标距离小于 d 的点集中,以纵坐标排序,并存储到 temp 数组中。这是为了后续在纵坐标差小于 d 的点对中进行最小距离的计算。

然后,遍历 temp 数组中的点,计算每对点之间的距离,并更新最小距离 d

最后,将计算得到的最小距离返回。

在 main 函数中,首先读取输入的点集,然后对点集进行排序,接着调用 merge 函数计算最小距离,并以保留4位小数的形式输出结果。

总结来说,temp 数组的排序操作是为了将左边区间中横坐标距离小于 d 的点按照纵坐标进行排序,以便后续计算纵坐标差小于 d 的点对的最小距离。这个排序操作是分治算法计算最小距离的一部分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乔冠宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值