标签:efi std 小数 题解 最小 分布 描述 sharp 包含
[BZOJ2458][BeiJing2011]最小三角形
试题描述
输入
输出
输入示例
4 1 1 2 3 3 3 3 4
输出示例
3.414214
数据规模及约定
100%的数据中N≤200000。
题解
平面分治。类似求平面最近点对。
首先对所有点按 x 坐标排序,每次选取中间的 x 作为分界点(令过这个点的竖直线为中线),左边、右边分别递归求,设求得的答案为 C;然后考虑跨中线的点对答案的贡献,找到中线左右扩展 C / 2 距离的矩形内的所有点,然后用一个边长为 C 的正方形从下往上平移,可以证明每次正方形框住的点只有常数个,暴力求正方形内所有点的答案即可(显然最终答案的那三个点是不可能在这个正方形之外的)。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cmath>
using namespace std;
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
return x * f;
}
#define maxn 200010
#define LL long long
const double ooe = 1.0 / 0.0, eps = 1e-5;
struct Vec {
LL x, y;
Vec() {}
Vec(int _, int __): x(_), y(__) {}
Vec operator - (const Vec& t) const { return Vec(x - t.x, y - t.y); }
double length() { return sqrt(x * x + y * y); }
bool operator < (const Vec& t) const { return x != t.x ? x < t.x : y < t.y; }
} ps[maxn], tmp[maxn];
bool cmp(Vec a, Vec b) { return a.y < b.y; }
int n, cnt;
double solve(int l, int r) {
if(r - l + 1 < 3) return ooe;
int mid = l + r >> 1;
double C = min(solve(l, mid), solve(mid + 1, r)), ans = C;
cnt = 0;
for(int i = l; i <= r; i++) if(abs(ps[i].x - ps[mid].x) - C * 0.5 <= eps) tmp[++cnt] = ps[i];
sort(tmp + 1, tmp + cnt + 1, cmp);
int L = 1, R = 3;
for(; R <= cnt; R++) {
while(tmp[R].y - tmp[L].y - C > eps) L++;
for(int x = L; x <= R; x++)
for(int y = x + 1; y <= R; y++)
for(int z = y + 1; z <= R; z++)
ans = min(ans, (tmp[x] - tmp[y]).length() + (tmp[x] - tmp[z]).length() + (tmp[y] - tmp[z]).length());
}
return ans;
}
int main() {
n = read();
for(int i = 1; i <= n; i++) {
int x = read(), y = read();
ps[i] = Vec(x, y);
}
sort(ps + 1, ps + n + 1);
printf("%.6lf\n", solve(1, n));
return 0;
}
标签:efi std 小数 题解 最小 分布 描述 sharp 包含
原文地址:http://www.cnblogs.com/xiao-ju-ruo-xjr/p/6953990.html