题目描述 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; }
总结:滑动窗口好难写。