[BZOJ2458][BeiJing2011]最小三角形

题目描述 Description

Xaviera现在遇到了一个有趣的问题。平面上有N个点,Xaviera想找出周长最小的三角形。由于点非常多,分布也非常乱,所以Xaviera想请你来解决这个问题。为了减小问题的难度,这里的三角形也包括共线的三点。

输入描述 Input Description

第一行包含一个整数N表示点的个数。接下来N行每行有两个整数,表示这个点的坐标。

输出描述 Output Description

输出只有一行,包含一个6位小数,为周长最短的三角形的周长(四舍五入)。

样例输入 Sample Input

4

1 1

2 3

3 3

3 4

样例输出 Sample Output

3.414214

数据范围及提示 Data Size & Hint

 

之前的一些废话:是时候准备会考了。。

题解:做法类似平面上求最近点对。首先把平面划分成两个部分,递归求出两个部分的答案为ans,然后,把离分割线距离小于ans/2的点全部加入队列,因为只有在这范围内答案才有可能比ans小,加入之后按照y坐标排一遍序,然后滑动窗口维护一下高度为ans/2的一个矩形,然后对矩形内的点暴力选,更新最优解即可。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef long long LL;
#define mem(a,b) memset(a,b,sizeof(a))
typedef pair<double,int> PDI;
const int maxn=200010;
const double oo=2147483647;
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
struct Point
{
    double x,y;
    Point() {}
    Point(double _1,double _2):x(_1),y(_2){}
    bool operator < (const Point &s)const
    {
        if(x==s.x)return y<s.y;
        return x<s.x;
    }
}p[maxn];
int n;double x,y;
PDI s[maxn];
double dis(double a,double b,double c,double d){
    return sqrt((c-a)*(c-a)+(d-b)*(d-b));
}
double triangle_perimeter(double a,double b,double c,double d,double e,double f){
    return dis(a,b,c,d)+dis(a,b,e,f)+dis(c,d,e,f);
}
bool cmp(PDI a,PDI b){return a.first<b.first;} 
double mdis(int l,int r)
{
    if(l+1>=r)return oo;
    if(l+2==r)return triangle_perimeter(p[l].x,p[l].y,p[l+1].x,p[l+1].y,p[r].x,p[r].y);
    int mid=(l+r)>>1,t=0;
    double d=min(mdis(l,mid),mdis(mid,r));
    for(int i=l;i<=r;i++)if(fabs(p[i].x-p[mid].x)<=d/2.0)s[t++]=make_pair(p[i].y,i); 
    sort(s,s+t,cmp);
    int st=0,ed;
    while(st<=t-2)
    {
        ed=st+1;
        while(fabs(s[ed].first-s[st].first)<=(d/2.0) && ed<=t-2)ed++;
        for(int i=st+1;i<ed;i++)for(int j=i+1;j<ed;j++)
            d=min(d,triangle_perimeter(p[s[st].second].x,p[s[st].second].y,p[s[i].second].x,p[s[i].second].y,p[s[j].second].x,p[s[j].second].y)); 
        st++;
    }
    return d;
}
int main()
{
    n=read();
    for(int i=0;i<n;i++)x=(double)read(),y=(double)read(),p[i]=Point(x,y);
    sort(p,p+n);
    printf("%.6lf\n",mdis(0,n-1));
    return 0;
}
View Code

总结:滑动窗口好难写。

posted @ 2017-06-21 18:31  小飞淙的云端  阅读(154)  评论(0编辑  收藏  举报