课本149页最近对问题
解析
最近对问题描述的就是在包含n个端的集合中找到距离最近的两个点,当然问题也可以定义在多维空间中,但是这里只是跟随书上的思路实现了二维情况下的最近对问题。假设所有讨论的点是以标准的笛卡尔坐标形式(x,y)给出的,那么在两个点Pi=(Xi,Yi)和Pj=(Xj,Yj)之间的距离是标准的欧几里得距离:
d(Pi,Pj)=sqrt( (X1-X2)2+(Y1-Y2)2 )
1、蛮力法
计算出所有的点之间的距离,然后找出距离最小的那一对,在这里增加效率的一种方式是只计算点下标 i<j 的那些对点之间的距离,这样就避免了重复计算同一对点间距离。
2、分治法
用分治法解决问题就是将集合s分为两个集合s1和s2。每个解合都有n/2个点,接着在子集和中递归求解最近的点。
设计
1、蛮力法
double get_min(int n)
{
double min = sqrt((P[0].x - P[1].x)*(P[0].x - P[1].x) + (P[0].y - P[1].y)*(P[0].y - P[1].y));
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
double t = sqrt((P[i].x - P[j].x)*(P[i].x - P[j].x) + (P[i].y - P[j].y)*(P[i].y - P[j].y));
if (min > t)
min = t;
}
}
return min;
}
2、分治法
double nearest(point S[], int left, int right) {
cout << left << " " << right << endl;
if (right - left == 1) {
return distance(S[right], S[left]);
}
if (right - left == 2) {
double d1 = distance(S[right], S[left]);
double d2 = distance(S[right], S[right + 1]);
double d3 = distance(S[right + 1], S[left]);
d2 = min(d1, d2);
d3 = min(d2, d3);
return d3;
}
int m = (right + left) / 2;
double d1 = nearest(S, left, m);
double d2 = nearest(S, m + 1, right);
double d = min(d1, d2);
int l = left, r = right;
while (S[l].x < S[m].x - d && l <= right);
l++;
while (S[r].x > S[m].x + d && r >= left)
r++;
sort(S + 1, S + r + 1, cmp2);
double d3;
for (int i = l; i <= r; i++) {
for (int j = i + 1; j <= r; j++) {
if (S[j].y - S[i].y >= d) {
break;
}
else {
d3 = distance(S[i], S[j]);
if (d3 < d)
d = d3;
}
}
}
return d;
}
分析
蛮力法的平均时间复杂度是Θ(n2)
分治法的平均时间复杂度是O(nlogn)
源码
https://github.com/pt0918/-/blob/master/Closest_pair_of_points_problem.cpp