对应HDU题目:点击打开链接
2 0 0 1 1 2 1 1 1 1 3 -1.5 0 0 0 0 1.5 0
0.71 0.00 0.75
题意:很裸,就是求平面里的最近点对。
思路:可采用分治的思想,把所有点按x递增排序。n个点的最近点对要么在左边的n/2个点中,要么在右边的n/2个点中。要么一个点在左边,一个点在右边组成最近点对。
难点在合并,也就是解决一个点在左边,一个点在右边组成最近点对这种情况。在mid左边跟右边的点要组成最近点对,设中间点的x坐标为x0,那符合要求的点的x坐标应该满足fabs(x - x0) <= 已求得的最小值min_d。那就可以把符合要求的点按y坐标递增排序。然后验证每个符合要求的点跟其他符合要求的点是否组成比min_d更小的距离。是就更新之。这里有个优化就是如果y值之差大于min_d,就可以跳出循环(y是按递增排序的)还有就是其实只需要计算每个点后面的7个点就可以了,《算法导论》计算几何那就有证明。。。
最后,用qsort超时了,改用sort就可以过。测试了下,sort的确比qsort快那么几倍,至少在windows中是这样。。。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <iostream> #include <algorithm> #define min(x, y) (x) < (y) ? (x) : (y) #define INF (1<<30) #define N 100100 using namespace std; int n; typedef struct { double x, y; }Point; Point p[N]; int a[N]; double Cal(const Point *p1, const Point *p2) { return sqrt((p1->x - p2->x) * (p1->x - p2->x) + (p1->y - p2->y) * (p1->y - p2->y)); } bool cmpx(Point p1, Point p2) { return p1.x < p2.x; } bool cmpy(int a, int b) { return p[a].y < p[b].y; } double Solve(int left, int right) { int i, j, cnt = 0; double d, d1, d2, min_d = INF; if(right - left < 3){ for(i=left; i<=right; i++) for(j=i+1; j<=right; j++){ d = Cal(p + i, p + j); min_d = min(d, min_d); } return min_d; } int mid = left + (right - left) / 2; d1 = Solve(left, mid); d2 = Solve(mid + 1, right); min_d = min(d1, d2); for(i=left; i<=right; i++) if(fabs(p[i].x - p[mid].x) <= min_d){ a[cnt++] = i; } sort(a, a + cnt, cmpy); for(i=0; i<cnt; i++){ for(j=i+1; j<cnt && j < 8; j++){ if(p[a[j]].y - p[a[i]].y >= min_d) break; d = Cal(p + a[i], p + a[j]); min_d = min(d, min_d); } } return min_d; } int main() { //freopen("in.txt", "r", stdin); while(scanf("%d", &n), n) { int i; for(i=0; i<n; i++){ scanf("%lf%lf", &p[i].x, &p[i].y); } sort(p, p + n, cmpx); double d = Solve(0, n - 1); printf("%.2lf\n", d / 2); } return 0; }