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

 

posted @ 2017-12-17 09:33  MSPqwq  阅读(245)  评论(0编辑  收藏  举报