BZOJ 2458
http://blog.csdn.net/PoPoQQQ/article/details/43155749
1.随便去三个点构成三角形的轴承作为ans的初值
2.按照x排序
3.分治处理[l,r]内的三角形的最小周长
4.分治[l,r]=>[l,mid]和[mid+1,r]
5.两个子区间的情况都以处理完毕,处理当前区间中点构成的三角形
6.按照纵坐标归并排序,将本层中与点mid的横坐标之差不超过ans/2的点拎出来
7.维护双指针,保证内部点纵坐标之差和横坐标与中线位置之差不超过ans/2,对于范围内的点暴力查找最小三角形即可
显而易见,期望的复杂度可能为O(nlogn)[逃]
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<math.h> #define FOR(i,s,t) for(register int i=s;i<=t;++i) #define ROF(i,s,t) for(register int i=s;i>=t;--i) using namespace std; typedef double db; int n; db ans; const int N=200011; struct point{ db x,y; inline bool operator<(point A)const{ return x<A.x||(x==A.x&&y<A.y); } }t[N],p[N]; inline double work(point A,point B){ return 1.00*sqrt((db)1.00*(A.x-B.x)*(A.x-B.x)+(db)1.00*(A.y-B.y)*(A.y-B.y)); } inline db abs(db x){ return x>0?x:-x; } inline db min(db a,db b){ return a<b?a:b; } inline void solve(int l,int r){ if(l==r)return; if(l+1==r){ if(p[r].y<p[l].y) swap(p[r],p[l]); return; } int mid=(l+r)>>1; int tmp=p[mid].x; solve(l,mid);solve(mid+1,r); int idx1=l,idx2=mid+1; FOR(i,l,r) t[i]=(idx2>r||(idx1<=mid&&p[idx1].y<p[idx2].y)?p[idx1++]:p[idx2++]); FOR(i,l,r)p[i]=t[i]; for(register int i=l,tail=l;i<=r;++i) if(1.00*abs(p[i].x-tmp)<ans/2){ for(;p[i].y-p[tail].y>ans/2;++tail); for(register int j=tail;j<i-1;++j) if(1.00*abs(p[j].x-tmp)<ans/2) if(p[i].y-p[j].y<ans/2) for(register int k=j+1;k<i;++k) ans=min(ans,work(p[i],p[j])+work(p[i],p[k])+work(p[j],p[k])); } } int main(){ scanf("%d",&n); FOR(i,1,n)scanf("%lf%lf",&p[i].x,&p[i].y); sort(p+1,p+n+1); ans=work(p[1],p[2])+work(p[3],p[2])+work(p[1],p[3]); solve(1,n); printf("%.6lf",ans); return 0; }