写的第一个分治。

解决两边各自的最小值很简单,合并这里要有小处理。

模板题为hdu1007.

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define FOR(i,x,y) for(int i=x;i<=y;++i)
using namespace std;
int n;
double ans;
struct k
{
    double x,y;
    int idx;
}f[100010],g[100010],s[100010];
bool cmp_x(k a,k b)
{
    return a.x<b.x;
}
bool cmp_y(k a,k b)
{
    return a.y<b.y;
}
double min2(double a,double b)
{
    if(a<b) return a;
    return b;
}
double dis(k a,k b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double dob_solve(k *a,k *b,k *c,int l,int r)
{
    int split=l,mid=(l+r)/2;
    double d1,d2,dm;
    if(r-l==1) return dis(a[l],a[r]);//只有两个元素
    if(r-l==2)//只有三个元素
    {
        double temp1,temp2,temp3;
        temp1=dis(a[l],a[l+1]);
        temp2=dis(a[l+1],a[r]);
        temp3=dis(a[l],a[r]);
        return min2(temp1,min2(temp2,temp3));
    }
    for(int i=l,j=l,k=mid+1;i<=r;++i)//把c分成两部分
        if(b[i].idx<=mid) c[j++]=b[i];
        else c[k++]=b[i];
    d1=dob_solve(a,c,b,l,mid);
    d2=dob_solve(a,c,b,mid+1,r);
    dm=min2(d1,d2);
    for(int i=l,j=mid+1,k=l;;)//合并两个部分
    {
        if(i>mid||j>r)
        {
            while(i<=mid) b[k++]=c[i++];
            while(j<=r) b[k++]=c[j++];
            break;
        }
        if(c[i].y>c[j].y) b[k++]=c[j++];
        else b[k++]=c[i++];
    }
    memcpy(c+l,b+l,(r-l+1)*sizeof(b[0]));
    FOR(i,l,r) if(fabs(b[i].x-b[mid].x)<dm) c[split++]=b[i];//找到x不超过dm
    FOR(i,l,split-2) FOR(j,i+1,split-1)//枚举y不超过dm
    {
        if(c[j].y-c[i].y<dm)
        {
            d1=dis(c[i],c[j]);
            dm=min2(dm,d1);
        }else break;
    }
    return dm;
}
int main()
{
    while(scanf("%d",&n)&&n)
    {
        FOR(i,0,n-1) scanf("%lf%lf",&f[i].x,&f[i].y);
        sort(f,f+n,cmp_x);//按x排序
        FOR(i,0,n-1) f[i].idx=i;
        memcpy(g,f,n*sizeof(f[0]));
        sort(g,g+n,cmp_y);//按y排序
        ans=dob_solve(f,g,s,0,n-1);
        printf("%.2f\n",ans/2.0);
    }
    return 0;
}