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;
}

浙公网安备 33010602011771号