题目大意:给出平面上一些点,问这些点组成的最小周长三角形的周长是多少。
思路:与平面最近点对类似的思想,先按照x值排序,通过全局目前搜到的最优解来缩小分治之后需要暴力枚举的范围。具体来说,递归的终止条件是需要处理的点数小于一定数量,就在这些点中暴力枚举来更新答案。这个值经过测定,在这个题中20左右为最快的。具体怎么算我也不知道。。
之后每处理一段区间,先递归处理左右区间来更新答案,弄出一个中轴来,设目前为止最优的答案是c,那么只保留距离中轴距离不超过c / 2的点来处理,不难证明在这之外的点不可能更新答案。
这些点中暴力枚举还是太多了,还需要一个小优化。对于左边的每个点来说,能够与这个点组成三角形的右边的两个点也是有限的。具体来说,y值相差超过c / 2的点是肯定不能与它组成三角形来更新答案的。这个在纸上画一画很显然就能够得到答案。
PS:写分治的时候要分清‘1’和‘l’啊。。
CODE:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define MAX 200010
#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);
}
}point[MAX],L[MAX],R[MAX];
inline bool cmp(const Point &p1,const Point &p2)
{
return p1.y < p2.y;
}
inline double Calc(const Point &p1,const Point &p2)
{
return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
int points;
double re = INF;
void Solve(int l,int r)
{
if(r - l <= 20) {
for(int i = l; i <= r; ++i)
for(int j = i + 1; j <= r; ++j)
for(int k = j + 1; k <= r; ++k)
re = min(re,Calc(point[i],point[j]) + Calc(point[j],point[k]) + Calc(point[k],point[i]));
return ;
}
int mid = (l + r) >> 1;
Solve(l,mid),Solve(mid + 1,r);
double x = (point[mid].x + point[mid + 1].x) / 2;
int ltop = 0,rtop = 0;
for(int i = mid; x - point[i].x < re / 2 && i; --i) L[++ltop] = point[i];
for(int i = mid + 1; point[i].x - x < re / 2 && i <= r; ++i) R[++rtop] = point[i];
sort(L + 1,L + ltop + 1,cmp);
sort(R + 1,R + rtop + 1,cmp);
int down = 1,up = 1;
for(int i = 1; i <= ltop; ++i) {
while(L[i].y - R[down].y > re / 2 && down < rtop) ++down;
while(R[up].y - L[i].y < re / 2 && up < rtop) ++up;
for(int j = down; j <= up; ++j)
for(int k = j + 1; k <= up; ++k)
re = min(re,Calc(L[i],R[j]) + Calc(L[i],R[k]) + Calc(R[j],R[k]));
}
down = up = 1;
for(int i = 1; i <= rtop; ++i) {
while(R[i].y - L[down].y > re / 2 && down < ltop) ++down;
while(L[up].y - R[i].y < re / 2 && up < ltop) ++up;
for(int j = down; j <= up; ++j)
for(int k = j + 1; k <= up; ++k)
re = min(re,Calc(R[i],L[j]) + Calc(R[i],L[k]) + Calc(L[j],L[k]));
}
}
int main()
{
cin >> points;
for(int i = 1; i <= points; ++i)
point[i].Read();
sort(point + 1,point + points + 1);
Solve(1,points);
cout << fixed << setprecision(6) << re << endl;
return 0;
}BZOJ 2458 BeiJing 2011 最小三角形 分治
原文地址:http://blog.csdn.net/jiangyuze831/article/details/42746423