UVA 10245 The Closest Pair Problem【分治】

题目链接:

http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=21269

题意:

求平面最近点对。

分析:

经典问题。
n比较大,直接枚举不可。
与上一道的树分治类似,我们也可以将点按照x坐标分成两类。
假设把所有点按照x坐标分成两类,那么有如下两种情况:

  1. 点p,q同属于左半边
  2. 点p,q一个属于左边一个属于右边

同样,对于第一种情况我们采用递归即可求解。
对于第二种情况,由于已经知道第一种情况下的最小距离d,所以我们只需考虑到划分的直线(x坐标为x0)的距离小于d的点,即坐标满足x0d<x<x0+d,而对于y坐标,每个点只需考虑y坐标比自己大的,且相差不超过d的点即可。

代码:

#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<cstdio>
using namespace std;
#define x first
#define y second
typedef pair<double, double>p;
const int maxn = 1e4 + 5, oo = 0x3f3f3f3f;
int n;
double eps = 1e-8;
p a[maxn];
bool cmp(p a, p b){return a.y < b.y;}
double solve(p* a, int n)
{
    if(n <= 1) return oo;
    int m = n / 2;
    double xx = a[m].x;
    double d = min(solve(a, m), solve(a + m, n - m));
    vector<p>b;
    for(int i = 0; i < n; i++){
        if(fabs(a[i].x - xx) <= d) b.push_back(a[i]);
    }
    sort(b.begin(), b.end(), cmp);
    for(int i = 0; i <b.size(); i++){
        for(int j = i + 1; j < b.size(); j++){
            double dx = b[j].x - b[i].x;
            double dy = b[j].y - b[i].y;
            if(dy - d >= eps) break;
            d = min(d, sqrt(dx * dx + dy * dy));
        }
    }
    return d;
}
int main (void)
{
    while(scanf("%d", &n) && n){
        double aa, bb;
        for(int i = 0 ; i < n; i++){
            scanf("%lf%lf", &aa, &bb);
            a[i] = p(aa, bb);
        }
        sort(a, a + n);
        double ans = solve(a, n);
        if(ans - 1e4 > eps) printf("INFINITY
") ;
        else printf("%.4f
", ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758646.html