题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2458
题意:平面上有N个点,输出周长最小的三角形的周长。
思路:按照x升序。分治。然后就是合并。设两边分治得到的答案为C。那么对于在中间线两边的点到中线的x距离小于C。将这些点按照y升序。对于每个点,找到y坐标差也在C范围内的暴力一下就行。
struct point
{
double x,y;
void get()
{
RD(x,y);
}
double len()
{
return sqrt(x*x+y*y);
}
point operator-(point a)
{
point p;
p.x=x-a.x;
p.y=y-a.y;
return p;
}
};
point a[N];
int n;
double len(point p) {return p.len();}
int cmp1(point a,point b)
{
return a.x<b.x;
}
int cmp2(point a,point b)
{
return a.y<b.y;
}
double cal(int L,int R)
{
double ans=dinf;
int i,j,k;
for(i=L;i<=R;i++) for(j=i+1;j<=R;j++)
{
for(k=j+1;k<=R;k++)
{
upMin(ans,len(a[i]-a[j])+len(a[i]-a[k])+len(a[j]-a[k]));
}
}
return ans;
}
point b[N],c[N],Q[N];
int bNum,cNum;
int qNum;
double combine(double x,int M,int L,int R)
{
bNum=cNum=0;
int now=M;
while(a[M].x-a[--now].x<=x&&now>=L) b[++bNum]=a[now];
now=M;
while(a[++now].x-a[M].x<=x&&now<=R) c[++cNum]=a[now];
c[++cNum]=a[M];
sort(b+1,b+1+bNum,cmp2);
sort(c+1,c+1+cNum,cmp2);
double ans=dinf;
int q=1,p=1;
qNum=0;
int i,j,k;
FOR1(i,bNum)
{
while(q<=cNum&&b[i].y-c[q].y>x) q++;
p=q;
while(p<=cNum&&c[p].y-b[i].y<=x) Q[++qNum]=c[p++];
for(j=1;j<=qNum;j++) for(k=1;k<=j-1;k++)
{
upMin(ans,len(b[i]-Q[j])+len(Q[j]-Q[k])+len(b[i]-Q[k]));
}
qNum=0;
}
q=1;p=1;cNum=0;
now=M;
while(a[++now].x-a[M].x<=x&&now<=R) c[++cNum]=a[now];
b[++bNum]=a[M];
sort(b+1,b+1+bNum,cmp2);
sort(c+1,c+1+cNum,cmp2);
FOR1(i,cNum)
{
while(q<=bNum&&c[i].y-b[q].y>x) q++;
p=q;
while(p<=bNum&&b[p].y-c[i].y<=x) Q[++qNum]=b[p++];
for(j=1;j<=qNum;j++) for(k=1;k<=j-1;k++)
{
upMin(ans,len(c[i]-Q[j])+len(Q[j]-Q[k])+len(c[i]-Q[k]));
}
qNum=0;
}
return ans;
}
double DFS(int L,int R)
{
double ans;;
int M=(L+R)>>1;
if(R-L+1>5)
{
ans=min(DFS(L,M+1),DFS(M+1,R));
upMin(ans,combine(ans,M+1,L,R));
}
else ans=cal(L,R);
return ans;
}
int main()
{
RD(n);
int i;
FOR1(i,n) a[i].get();
sort(a+1,a+n+1,cmp1);
double ans=DFS(1,n);
PR(ans);
}