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

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42913023

题解:很经典的分治计算几何模型。

我们对点的x坐标排序,然后进行分治,同时分治完了还需要求两边的互相影响。

一、在左边取两个点,右边一个。

二、在右边取两个点,左边一个。

这个时候我们可以对左右两边的点再分别按照y值排序,

当然,因为已经出来了一个比较优的ans,所以当一个点距离两边中界过远,那么我们就把它扔掉再不用管了。

还有就是两边的点,y坐标距离过大的也不能进行选择,所以又进行一次剪枝。

然后就是暴力枚举,但是每个点在左边/右边选择的那两个点是有范围的(就是上述剪枝)。

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 201000
#define inf 1e15
using namespace std;

struct Point
{
	double x,y;
	bool operator < (const Point &a)const{return x<a.x;}
	void read(){scanf("%lf%lf",&x,&y);}
}p[N],L[N],R[N];
inline bool cmp(const Point &a,const Point &b){return a.y<b.y;}
inline double Calc(Point &a,Point &b,Point &c){return
	sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))+
	sqrt((a.x-c.x)*(a.x-c.x)+(a.y-c.y)*(a.y-c.y))+
	sqrt((b.x-c.x)*(b.x-c.x)+(b.y-c.y)*(b.y-c.y));
}
int n;
double ans=inf;
void solve(int l,int r)
{
	int i,j,k;
	if(r-l<=20)
	{
		for(i=l;i<=r;i++)
			for(j=i+1;j<=r;j++)
				for(k=j+1;k<=r;k++)
					ans=min(ans,Calc(p[i],p[j],p[k]));
		return ;
	}
	int mid=l+r>>1;
	solve(l,mid),solve(mid+1,r);

	// 处理两段区间中间的影响
	double x=(p[mid].x+p[mid+1].x)/2;
	int ltop=0,rtop=0;
	for(i=mid  ;i   &&x-p[i].x<ans/2;i--)L[++ltop]=p[i];
	for(i=mid+1;i<=r&&p[i].x-x<ans/2;i++)R[++rtop]=p[i];
	sort(L+1,L+ltop+1,cmp);
	sort(R+1,R+rtop+1,cmp);

	int top=1,tail=1;
	for(i=1;i<=ltop;i++) // 左边一个点,右边两个点
	{
		while(L[i].y-R[top].y >ans/2&&top <rtop)++top;
		while(R[tail].y-L[i].y<ans/2&&tail<rtop)++tail;
		for(j=top;j<=tail;j++)
			for(k=j+1;k<=tail;k++)
				ans=min(ans,Calc(L[i],R[j],R[k]));
	}
	top=tail=1;
	for(i=1;i<=rtop;i++) // 右边一个点,左边两个点
	{
		while(R[i].y-L[top].y >ans/2&&top<ltop)++top;
		while(L[tail].y-R[i].y<ans/2&&tail <ltop)++tail;
		for(j=top;j<=tail;j++)
			for(k=j+1;k<=tail;k++)
				ans=min(ans,Calc(R[i],L[j],L[k]));
	}
}
int main()
{
//	freopen("test.in","r",stdin);
	int i,j,k;
	scanf("%d",&n);
	for(i=1;i<=n;i++)p[i].read();
	sort(p+1,p+n+1);
	solve(1,n);
	printf("%.6lf\n",ans);
	return 0;
}
时间: 2024-10-15 01:56:21

【BZOJ2458】【BeiJing2011】最小三角形 计算几何+分治的相关文章

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

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

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

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

BZOJ2458 [BeiJing2011]最小三角形

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

BZOJ 2458: [BeiJing2011]最小三角形 | 平面分治

题目: 给出若干个点 求三个点构成的周长最小的三角形的周长(我们认为共线的三点也算三角形) 题解: 可以参考平面最近点对的做法 只不过合并的时候改成枚举三个点更新周长最小值,其他的和最近点对大同小异 2#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define N 200010 #define INF 1e20 using namespace std; int

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){

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想请你来解决问题. 为了减小问题的难度,这里的三

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

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

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

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

BZOJ 2458 BeiJing 2011 最小三角形 分治

题目大意:给出平面上一些点,问这些点组成的最小周长三角形的周长是多少. 思路:与平面最近点对类似的思想,先按照x值排序,通过全局目前搜到的最优解来缩小分治之后需要暴力枚举的范围.具体来说,递归的终止条件是需要处理的点数小于一定数量,就在这些点中暴力枚举来更新答案.这个值经过测定,在这个题中20左右为最快的.具体怎么算我也不知道.. 之后每处理一段区间,先递归处理左右区间来更新答案,弄出一个中轴来,设目前为止最优的答案是c,那么只保留距离中轴距离不超过c / 2的点来处理,不难证明在这之外的点不可