题意:求最近点对
暴力一定超时,分治:(代码参考别人)
求最大的环,此环只能套中一个,所以只能先找出距离最小的两点且其距离就是环的直径,不然该环就有可能一次套中两个环。所以这题的题意是:求最近点对。
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#define DX(x) ((x)*(x))
using namespace std;
const int MAX=100000+1;
int n;
struct Point
{
double x,y;
int index;
}a[MAX],b[MAX],c[MAX];
double getdis(Point a,Point b)
{
return sqrt(DX(a.x-b.x)+DX(a.y-b.y));
}
/*double getmin(double a,double b)
{
if(a<b) return a;
else return b;
}*/
inline double getmin(double a, double b)
{
return a < b ? a : b;
}
bool cmpx(const Point& a,const Point& b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
bool cmpy(const Point& a,const Point& b)
{
if(a.y==b.y) return a.x<b.x;
return a.y<b.y;
}
void merget(Point b[],Point c[],int p,int m,int q) //合并
{
int i,j,k;
for(i=p,k=p,j=m+1;i<=m&&j<=q;) //两边都是按y从小到大排列,所以只用比较
//两边的最左方的y值,即可得总的y的升序排列
{
if(c[i].y>c[k].y) b[k++]=c[i], j++;
else b[k++]=c[i],i++;
}
while(i<=m) b[k++]=c[i++];
while(j<=q) b[k++]=c[j++];
}
double closet(Point a[],Point b[],Point c[],int p,int q)
{
double d1,d2;
if(q - p == 1) return getdis(a[p],a[q]);
if(q - p == 2)
{
double x1=getdis(a[p],a[p+1]);
double x2=getdis(a[p],a[q]);
double x3=getdis(a[p+1],a[q]);
return getmin(x1,getmin(x2,x3));
}
int m=(q + p)/2,i,j,k;
//为了正确 的分治、
for(i = p,j = p,k = m + 1; i <=q; ++i)
{
if(b[i].index<=m) c[j++]=b[i];
else c[k++]=b[i];
}
d1=closet(a,c,b,p,m);
d2=closet(a,c,b,m+1,q);
merget(b,c,p,m,q);
double dm=getmin(d1,d2);
for(i = p, k = p;i <= q;++i)
{
if(fabs(b[i].x-b[m].x) < dm)
c[k++]=b[i];
}
for(i = p; i < k; ++i)
{
for(j = i + 1; j < k && c[j].y - c[i].y < dm; ++j)
{
double temp=getdis(c[i],c[j]);
if(temp < dm) dm=temp;
}
}
return dm;
}
int main()
{
while(scanf("%d",&n)!=EOF&&n!=0)
{
for(int i=0;i<n;i++)
{scanf("%lf%lf",&a[i].x,&a[i].y); }
sort(a,a+n,cmpx);
for(int i=0;i<n;i++) a[i].index=i;
memcpy(b,a,n*sizeof(b[0]));
sort(b,b+n,cmpy);
double dis=closet(a,b,c,0,n-1);
printf("%.2lf\n",dis/2.0);
}
return 0;
}
注1: