【GCJ2009B】Min Perimeter:
给你一个整数坐标的点集,询问点集中最小的三角形周长是多少。退化的三角形也是允许的(面积为0)。
0<n<=100000
0
<
n
<=
100000
题解:
没有结合所学的知识,于是没有想出来。
记得以前学过平面最近点对。
利用分治法,和一个结论,2d*d的矩形里,每个点相互的距离不超过d,最多可以摆6个点。
这题也可以分治,并且大胆猜测结论,可能的点数也是常数级别的,于是就行了。
Code:
#include<cmath>
#include<cstdio>
#include<algorithm>
#define db double
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
const int N = 1e5 + 5;
int n, d[N], st, en;
struct node {
int x, y;
} a[N];
db p;
db dis(node a, node b) {return sqrt((db) (a.x - b.x) * (a.x - b.x) + (db) (a.y - b.y) * (a.y - b.y));}
int cmp(node a, node b) {return a.x < b.x;}
int cmp2(node a, node b) {return a.y < b.y;}
db solve(int x, int y, int z) {return dis(a[x], a[y]) + dis(a[x], a[z]) + dis(a[y], a[z]);}
void dg(int x, int y) {
if(x == y) return;
int m = x + y >> 1;
dg(x, m); dg(m + 1, y);
int u = a[m].x;
sort(a + x, a + y + 1, cmp2);
st = 1; en = 0;
fo(i, x, y) {
while(st <= en && a[i].y - a[d[st]].y > p) st ++;
if(a[i].x >= u - p / 2 && a[i].x <= u + p / 2) {
fo(j, st, en - 1) fo(k, j + 1, en)
p = min(p, solve(i, d[j], d[k]));
d[++ en] = i;
}
}
}
int main() {
scanf("%d", &n);
fo(i, 1, n) scanf("%d %d", &a[i].x, &a[i].y);
sort(a + 1, a + n + 1, cmp);
p = 1e18; dg(1, n);
printf("%.10lf", p);
}