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

  

posted @ 2017-11-28 11:33  Stump  阅读(177)  评论(0编辑  收藏  举报