传送门
题意:平面上有N个点,找出周长最小的三角形.注意:这里的三角形也包括共线的三点.
分析:回忆一下平面最近点对问题:平面上有N个点,找出距离最近的两个点.显然,本题唯一的不同之处在于要找三个点.所以我们仍然可以套平面最近点对问题的板子,只是稍微修改一下递归边界,注意一下求距离的时候是求三个点两两之间距离之和就可以了.
最后提醒一下,本题爆int.
蒟蒻的平面最近点对学习笔记
LL n,b[200005];
struct point{
LL x,y;
}a[200005];
bool cmpx(point x,point y){return x.x<y.x;}
bool cmpy(const LL &x,const LL &y){return a[x].y<a[y].y;}
double pf(LL x){return x*x*1.0;}
double dis(point x,point y,point z){
return sqrt(pf((x.x-y.x))+pf((x.y-y.y)))+sqrt(pf((x.x-z.x))+pf(x.y-z.y))+sqrt(pf((y.x-z.x))+pf(y.y-z.y));
}
double solve(LL l,LL r){
if(l+1>=r)return 1e18;
if(l+2==r)return dis(a[l],a[l+1],a[r]);
//注意一下求三个点与两个点的边界条件不同
LL mid=(l+r)>>1;
double midline=(a[mid].x+a[mid+1].x)/2;
double d=min(solve(l,mid),solve(mid+1,r));
LL cnt=0;
for(int i=l;i<=r;i++)
if(fabs(a[i].x-midline)<=d)
b[++cnt]=i;
sort(b+1,b+cnt+1,cmpy);
for(int i=1;i<cnt;i++)
for(int j=i+1;j<cnt;j++){
if((a[b[j]].y-a[b[i]].y)>d)break;
//不符合要求需要直接break掉,下面同理
//如果只是if(符合要求)...这样就会超时.
for(int k=j+1;k<=cnt;k++){
if((a[b[k]].y-a[b[j]].y)>d)break;
double dist=dis(a[b[i]],a[b[j]],a[b[k]]);
if(dist<d)d=dist;
}
}
return d;
}
signed main(){
n=read();
for(int i=1;i<=n;i++){
a[i].x=read();
a[i].y=read();
}
sort(a+1,a+n+1,cmpx);
printf("%.6lf
",solve(1,n));
return 0;
}