BZOJ 2458: [BeiJing2011]最小三角形 | 平面分治
题目:
给出若干个点
求三个点构成的周长最小的三角形的周长(我们认为共线的三点也算三角形)
题解:
可以参考平面最近点对的做法
只不过合并的时候改成枚举三个点更新周长最小值,其他的和最近点对大同小异
2#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define N 200010 #define INF 1e20 using namespace std; int n; struct point { double x,y; point () {}; point (double _x,double _y) { x=_x,y=_y; } point operator - (const point &a)const { return point(x-a.x,y-a.y); } bool operator < (const point &a)const { return x<a.x; } double norm() { return sqrt(x*x+y*y); } }p[N]; double calc(const point &x,const point &y,const point &z) { return (x-y).norm()+(y-z).norm()+(x-z).norm(); } double solve(int l,int r) { if (r==l) return INF; int mid=l+r>>1; double xmid=(p[mid].x+p[mid+1].x)/2; double ret=min(solve(l,mid),solve(mid+1,r)); static point a[N],b[N],c[N]; int pos=l,i=l,j=mid+1,b_n=0,c_n=0; while (pos<=r) { if (i<=mid && (p[i].y<p[j].y || j>r)) { if (p[i].x+ret/2>xmid) b[++b_n]=p[i]; a[pos++]=p[i++]; } else { if (p[j].x-ret/2<xmid) c[++c_n]=p[j]; a[pos++]=p[j++]; } } for (i=l;i<=r;i++) p[i]=a[i]; if (r-l<2) return INF; /* for (int i=1;i<=b_n;i++) for (int j=i+1;j<=b_n;j++) for (int k=1;k<=c_n;k++) if (i!=j) ret=min(ret,(b[i]-b[j]).norm()+(b[i]-c[k]).norm()+(b[j]-c[k]).norm()); for (int i=1;i<=b_n;i++) for (int j=1;j<=c_n;j++) for (int k=j+1;k<=c_n;k++) if (j!=k) ret=min(ret,(b[i]-c[j]).norm()+(b[i]-c[k]).norm()+(c[j]-c[k]).norm()); */ // /* for (int i=1,j=1;i<=b_n;i++) { while (j<=c_n && b[i].y-c[j].y>ret/2) j++; for (int k=j;k<=c_n && abs(b[i].y-c[k].y)<ret/2;k++) for (int h=k+1;h<=c_n && abs(b[i].y-c[h].y)<ret/2;h++) ret=min(ret,calc(b[i],c[k],c[h])); } for (int i=1,j=1;i<=c_n;i++) { while (j<=b_n && c[i].y-b[j].y>ret/2) j++; for (int k=j;k<=b_n && abs(c[i].y-b[k].y)<ret/2;k++) for (int h=k+1;h<=b_n && abs(c[i].y-b[h].y)<ret/2;h++) ret=min(ret,calc(c[i],b[k],b[h])); } // */ return ret; } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); sort(p+1,p+1+n); printf("%.6lf",solve(1,n)); return 0; }