编程之美2.11节。
对于扩展问题2,可以先找到这些点的凸包(O(nlogn)),然后对凸包点求最大距离。对于凸包点,可以考虑按长轴平分四份,然后在最外侧的两份之间寻找最大点对。因为居内侧的两份中的最大距离无法超过长轴。当然,可以分割得更精细一点。这只是计算上复杂性的小差别了。
struct
Point {
double x, y;
};
double dist( const Point & p1, const Point & p2) {
double dx = p1.x - p2.x, dy = p1.y - p2.y;
return sqrt(dx * dx + dy * dy);
}
struct Compare {
bool x;
Compare( bool xx): x(xx) {}
bool operator ()( const Point & p, const Point & q) {
return x ? p.x < q.x: p.y < q.y;
}
};
double closest(vector < Point > ::iterator first, vector < Point > ::iterator last) {
typedef vector < Point > ::iterator It;
double r = MAX_DIST ;
if (last - first < 64 ) {
for (It it = first; it != last; ++ it) {
for (It it2 = it + 1 ; it2 != last; ++ it2) {
double d = dist( * it, * it2);
if (d < r) r = d;
}
}
return r;
}
Point pmin, pmax;
pmin = pmax = * first;
for (It it = first + 1 ; it != last; ++ it) {
if (it -> x < pmin.x) pmin.x = it -> x;
if (it -> y < pmin.y) pmin.y = it -> y;
if (it -> x > pmax.x) pmax.x = it -> x;
if (it -> y > pmax.y) pmax.y = it -> y;
}
bool px = pmax.y - pmin.y < pmax.x - pmin.x;
It mid = first + (last - first) / 2 ;
nth_element(first, mid, last, Compare(px));
double v = px ? mid -> x: mid -> y;
r = min(closest(first, mid), closest(mid, last));
vector < Point > vec;
for (It it = first; it != last; ++ it)
if (fabs(px ? it -> x - v: it -> y - v) < r)
vec.push_back( * it);
sort(vec.begin(), vec.end(), Compare( ! px));
if (vec.end() - vec.begin() >= 8 ) {
for (It it = vec.begin() + 8 ; it <= vec.end(); ++ it) {
double cr = closest(it - 8 , it);
if (cr < r) r = cr;
}
}
else {
double cr = closest(vec.begin(), vec.end());
if (cr < r) r = cr;
}
return r;
}
double x, y;
};
double dist( const Point & p1, const Point & p2) {
double dx = p1.x - p2.x, dy = p1.y - p2.y;
return sqrt(dx * dx + dy * dy);
}
struct Compare {
bool x;
Compare( bool xx): x(xx) {}
bool operator ()( const Point & p, const Point & q) {
return x ? p.x < q.x: p.y < q.y;
}
};
double closest(vector < Point > ::iterator first, vector < Point > ::iterator last) {
typedef vector < Point > ::iterator It;
double r = MAX_DIST ;
if (last - first < 64 ) {
for (It it = first; it != last; ++ it) {
for (It it2 = it + 1 ; it2 != last; ++ it2) {
double d = dist( * it, * it2);
if (d < r) r = d;
}
}
return r;
}
Point pmin, pmax;
pmin = pmax = * first;
for (It it = first + 1 ; it != last; ++ it) {
if (it -> x < pmin.x) pmin.x = it -> x;
if (it -> y < pmin.y) pmin.y = it -> y;
if (it -> x > pmax.x) pmax.x = it -> x;
if (it -> y > pmax.y) pmax.y = it -> y;
}
bool px = pmax.y - pmin.y < pmax.x - pmin.x;
It mid = first + (last - first) / 2 ;
nth_element(first, mid, last, Compare(px));
double v = px ? mid -> x: mid -> y;
r = min(closest(first, mid), closest(mid, last));
vector < Point > vec;
for (It it = first; it != last; ++ it)
if (fabs(px ? it -> x - v: it -> y - v) < r)
vec.push_back( * it);
sort(vec.begin(), vec.end(), Compare( ! px));
if (vec.end() - vec.begin() >= 8 ) {
for (It it = vec.begin() + 8 ; it <= vec.end(); ++ it) {
double cr = closest(it - 8 , it);
if (cr < r) r = cr;
}
}
else {
double cr = closest(vec.begin(), vec.end());
if (cr < r) r = cr;
}
return r;
}