最近点对问题(暴力,分治)

最近点对问题

问题简述:

给你n个点,让你求出最近的两个点的距离。
第一行输入一个整数n,接下来n行,每行两个数,表示点的横纵坐标。

测试样例:
12
-1 3
-2 -2
1 -4
2 1
1 5
3 3
3 0
5 1
7 3
7 6
5 6
3 7

输出结果:
1.41421

Solve方法
暴力法: 理所当然,就是遍历所有的点,求出所有可能的结果,取最小值。
时间复杂度:O(n^2)

/*
最近点对问题------暴力法
*/
#include<iostream>
#include<float.h>
#include<math.h>
using namespace std;
const int maxn = 1e5 + 5;
struct node{
    double x,y;
}a[maxn];

void solve(int n){
    int p1 = 0, p2 = 0;
    double min_dis = DBL_MAX;
    for(int i = 0; i < n; i++){
        for(int j = i + 1; j < n; j++){
            double x = (a[i].x - a[j].x) * (a[i].x - a[j].x);
            double y = (a[i].y - a[j].y) * (a[i].y - a[j].y);
            double dis = x + y;
            if(dis < min_dis){
                min_dis = dis;
                p1 = i;
                p2 = j;
            }
        }
    }
    cout << "最近点对为点" << p1 << "和点" << p2 << endl;
    cout << "最近点对的距离为" << sqrt(min_dis) << endl;
}

int main()
{
    int n;
    cin >> n;
    for(int i = 0; i < n; i++)
        cin >> a[i].x >> a[i].y;
    solve(n);
    return 0;
}

分治法:
用分治法解决最近点对问题,很自然的想法就是将这个集合分成两个子集S1和S2,每个子集中有n/2个点,然后在每个子集中递归求其最近点对。
在这里插入图片描述
当然,在这过程中要注意一种特殊情况,就是在求完每个子集的最近点对合并的时候,从在一个漏洞,那就是中轴线两边的点还没有考虑(这个图中表现为p3和q3),此时还需在求一下中轴线两端最近点对的情况。
在这里插入图片描述

/*
最近点对问题------分治法
*/
#include<iostream>
#include<math.h>
#include<algorithm>
#include<float.h>
using namespace std;
const int maxn = 1e5 + 5;
struct node{
    double x, y;
}p[maxn], q[maxn];
bool cmp(node a, node b){
    return a.x < b.x;
}
bool cmp1(node a, node b){
    return a.y < b.y;
}
double solve_dis(node a, node b){
    double x = (a.x - b.x) * (a.x - b.x);
    double y = (a.y - b.y) * (a.y - b.y);
    return sqrt(x + y);
}
double solve(node p[], int l, int r){
    if(l == r)
        return FLT_MAX;
    if(r - l == 1)
        return solve_dis(p[l], p[r]);
    int mid = (l + r) / 2;
    double res = min(solve(p, l, mid), solve(p, mid + 1, r));
    int t = 0;
    for(int i = l; i <= r; i++){
        if(fabs(p[i].x - p[mid].x) <= res)
            q[t++] = p[i];
    }
    sort(q, q + t, cmp1);
    for(int i = 0; i < t; i++){
        for(int j = i + 1; j < t; j++){
            if(q[j].y - q[i].y > res)
                break;
            res = min(res, solve_dis(q[i], q[j]));
        }
    }
    return res;
}
int main()
{
    int n; cin >> n;
    for(int i = 0; i < n; i++)
        cin >> p[i].x >> p[i].y;
    sort(p, p + n, cmp);
    double ans = solve(p, 0, n - 1);
    cout << "最近点对的距离为:" << ans << endl;
    return 0;
}
发布了40 篇原创文章 · 获赞 6 · 访问量 1394

猜你喜欢

转载自blog.csdn.net/qq_43321732/article/details/104674977
今日推荐