写的第一个分治。
解决两边各自的最小值很简单,合并这里要有小处理。
模板题为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;
}
浙公网安备 33010602011771号