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;
}
时间: 2025-01-12 09:08:24

BZOJ 2458: [BeiJing2011]最小三角形 | 平面分治的相关文章

BZOJ 2458 BeiJing2011 最小三角形 计算几何+分治

题目大意:给定平面上的一个点集,求这个点集所能组成的周长最小的三角形 与平面最近点对一个道理- - 这个题也是分治做法 做法如下: 1.记录全局答案ans 2.将所有点按照x值排序 3.定义Solve(l,r)为处理[l,r]区间内的最小三角形 4.对于每层Solve(l,r),将当前区间分成左右两部分,分别递归处理 5.两侧的最小三角形都以处理完毕,现在我们要处理的就是两区间之间的点构成的三角形 6.将本层中与点mid的横坐标之差不超过ans/2的点拎出来,按照纵坐标排序 (其实这步可以直接递

bzoj 2458: [BeiJing2011]最小三角形 题解

[前言]话说好久没有写题解了.到暑假了反而忙.o(╯□╰)o [原题] 2458: [BeiJing2011]最小三角形 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 574  Solved: 177 [Submit][Status] Description Xaviera如今遇到了一个有趣的问题. 平面上有N个点.Xaviera想找出周长最小的三角形. 因为点许多.分布也很乱,所以Xaviera想请你来解决问题. 为了减小问题的难度,这里的三

bzoj2458: [BeiJing2011]最小三角形(分治+几何)

题目链接:bzoj2458: [BeiJing2011]最小三角形 学习推荐博客:分治法编程问题之最接近点对问题的算法分析 题解:先将所有点按x值排列,然后每次将当前区间[l,r]分成左右两半递归求解周长最小三角形.考虑到两半区间之间可能有连成最小三角形的情况,设dd为两半区间中最小三角形周长的最小值,筛选满足要求的点(x值与中点坐标x值的距离小于dd),然后按y值排序,进而暴搜出周长最小三角形. 1 #include<cstdio> 2 #include<cmath> 3 #in

BZOJ 2458 最小三角形 | 平面分治

BZOJ 2458 最小三角形 题面 一个平面上有很多点,求他们中的点组成的周长最小的三角形的周长. 题解 跟平面最近点对差不多,也是先把区间内的点按x坐标从中间分开,递归处理,然后再处理横跨中线的三角形. 如何缩小范围?设左右两个子区间发现的最小周长是d,则与中线距离超过d / 2都没有用了,对于一个点,所有与它距离超过d / 2的点也都没有用. #include <cstdio> #include <cstring> #include <cmath> #includ

【BZOJ2458】【BeiJing2011】最小三角形 计算几何+分治

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42913023 题解:很经典的分治计算几何模型. 我们对点的x坐标排序,然后进行分治,同时分治完了还需要求两边的互相影响. 一.在左边取两个点,右边一个. 二.在右边取两个点,左边一个. 这个时候我们可以对左右两边的点再分别按照y值排序, 当然,因为已经出来了一个比较优的ans,所以当一个点距离两边中界过远,那么我们就把它扔掉再不用管了. 还有就是两边的点,y坐标距离过大的也不能进行选择,

BZOJ2458 [BeiJing2011]最小三角形

Description Xaviera现在遇到了一个有趣的问题. 平面上有N个点,Xaviera想找出周长最小的三角形. 由于点非常多,分布也非常乱,所以Xaviera想请你来解决这个问题. 为了减小问题的难度,这里的三角形也包括共线的三点. Input 第一行包含一个整数N表示点的个数. 接下来N行每行有两个整数,表示这个点的坐标. Output 输出只有一行,包含一个6位小数,为周长最短的三角形的周长(四舍五入). Sample Input 4 1 1 2 3 3 3 3 4 Sample

bzoj2458: [BeiJing2011]最小三角形 最近点对

类似分治最近点对的方法乱搞一下就行. #include<bits/stdc++.h> #define N 200010 #define M (s+t>>1) using namespace std; struct vec{ int x,y; }u[N],v[N]; bool foo(vec a,vec b){ return a.x<b.x; } bool bar(vec a,vec b){ return a.y<b.y; } double sqr(double x){

【模板】【计几】旋转坐标(用于最小三角形以及三角形四边形面积存在性问题)

发现计算几何算法(瞎搞)真的是博大精深. 最大三角形和最大四边形都是旋转卡壳,有模板的.这里的方法还可以求最小三角形还有最小四边形,以及三角形面积存在性问题. 求最小三角形面积(n平方):bzoj3707. 参考:http://www.pianshen.com/article/772191644/ 其实就是先把n方个直线按照斜率先排了序,然后所有点按照距离y轴距离排序(距离有正负),然后枚举的直线相当于y轴,每一次旋转 “ y轴 ” 的时候维护一下这个序列.然后我们发现维护这个序列只需要交换现在

Codeforces 97B Superset 平面分治

题目链接:点击打开链接 题意: 给定一个点集 添加一些点后再把这个点集输出来. 添加完点后使得对于点集内任意2个点都满足下面2条中至少一条 1.在同一水平线上或在同一垂直线上 2.所围成的矩阵里有其他点. 思路: 平面分治 先把点按x轴排序,然后找到中间的点,做一条直线 x = a[mid].x; 然后把所有点都投影到这条直线上,那么对于左边的点就不需要再和右边的进行匹配了. #pragma comment(linker, "/STACK:1024000000,1024000000")