1. 程式人生 > >【HDU1007】Quoit Design(分治求平面最近點對)

【HDU1007】Quoit Design(分治求平面最近點對)

假設當前區間為[l,r] 中間點為mid

那麼最近點對 要麼在[1,l]中,要麼在[l+1,r]中,要麼兩邊各有一個

我們遞迴處理出左區間的 最近點對距離d1 右區間d2 取d=min(d1,d2)

然後有兩個剪枝來處理情況3

1.按x為關鍵字排個序,列舉[l,r]的點,假如一個點的x與中間點的x差值已經超過了d,那肯定不滿足要求,因為還要算上y

2.剪枝1還不夠,當我們已經篩選出符合剪枝1的點後,把這些點又按照y為關鍵字排個序,同樣的,假如一個點的y與當前點的x差值已經超過了d,那他之後的點都是不滿足要求的,可以break掉,然後順便統計答案

#include<bits/stdc++.h>
#define N 100005
using namespace std;
struct Node
{
    double x,y;
}p[N];
int n;
inline bool cmp1(const Node &a,const Node &b)
{
    if(a.x==b.x)    return a.y<b.y;
    return a.x<b.x;
}
inline bool cmp2(const int &a,const int &b)
{
    return p[a].y<p[b].y;
}
double dis(Node a,Node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int temp[N];
double solve(int l,int r)
{
    if(l+1==r)  return dis(p[l],p[r]);
    if(l+2==r)  return min(dis(p[l],p[r]),min(dis(p[l+1],p[r]),dis(p[l],p[l+1])));
    int mid=(l+r)>>1;
    double d=min(solve(l,mid),solve(mid+1,r));
    int cnt=0;
    for(int i=l;i<=r;i++)
    {
        if(p[i].x>=p[mid].x-d&&p[mid].x+d>=p[i].x)
            temp[++cnt]=i;
    }
    sort(temp+1,temp+cnt+1,cmp2);
    for(int i=1;i<=cnt;i++)
    {
        for(int j=i+1;j<=cnt;j++)
        {
            if(p[temp[j]].y-p[temp[i]].y>=d)    break;
            d=min(d,dis(p[temp[i]],p[temp[j]]));
        } 
    }
    return d;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL),cout.tie(NULL);
    while(cin>>n&&n)
    {
        for(int i=1;i<=n;i++)   cin>>p[i].x>>p[i].y;
        sort(p+1,p+n+1,cmp1);
        cout<<fixed<<setprecision(2)<<solve(1,n)/2<<'\n';
    }
    return 0;
}