最近点对问题
问题简述:
给你n个点,让你求出最近的两个点的距离。
第一行输入一个整数n,接下来n行,每行两个数,表示点的横纵坐标。
测试样例:
12
-1 3
-2 -2
1 -4
2 1
1 5
3 3
3 0
5 1
7 3
7 6
5 6
3 7
输出结果:
1.41421
Solve方法
暴力法: 理所当然,就是遍历所有的点,求出所有可能的结果,取最小值。
时间复杂度:O(n^2)
/*
最近点对问题------暴力法
*/
#include<iostream>
#include<float.h>
#include<math.h>
using namespace std;
const int maxn = 1e5 + 5;
struct node{
double x,y;
}a[maxn];
void solve(int n){
int p1 = 0, p2 = 0;
double min_dis = DBL_MAX;
for(int i = 0; i < n; i++){
for(int j = i + 1; j < n; j++){
double x = (a[i].x - a[j].x) * (a[i].x - a[j].x);
double y = (a[i].y - a[j].y) * (a[i].y - a[j].y);
double dis = x + y;
if(dis < min_dis){
min_dis = dis;
p1 = i;
p2 = j;
}
}
}
cout << "最近点对为点" << p1 << "和点" << p2 << endl;
cout << "最近点对的距离为" << sqrt(min_dis) << endl;
}
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++)
cin >> a[i].x >> a[i].y;
solve(n);
return 0;
}
分治法:
用分治法解决最近点对问题,很自然的想法就是将这个集合分成两个子集S1和S2,每个子集中有n/2个点,然后在每个子集中递归求其最近点对。
当然,在这过程中要注意一种特殊情况,就是在求完每个子集的最近点对合并的时候,从在一个漏洞,那就是中轴线两边的点还没有考虑(这个图中表现为p3和q3),此时还需在求一下中轴线两端最近点对的情况。
/*
最近点对问题------分治法
*/
#include<iostream>
#include<math.h>
#include<algorithm>
#include<float.h>
using namespace std;
const int maxn = 1e5 + 5;
struct node{
double x, y;
}p[maxn], q[maxn];
bool cmp(node a, node b){
return a.x < b.x;
}
bool cmp1(node a, node b){
return a.y < b.y;
}
double solve_dis(node a, node b){
double x = (a.x - b.x) * (a.x - b.x);
double y = (a.y - b.y) * (a.y - b.y);
return sqrt(x + y);
}
double solve(node p[], int l, int r){
if(l == r)
return FLT_MAX;
if(r - l == 1)
return solve_dis(p[l], p[r]);
int mid = (l + r) / 2;
double res = min(solve(p, l, mid), solve(p, mid + 1, r));
int t = 0;
for(int i = l; i <= r; i++){
if(fabs(p[i].x - p[mid].x) <= res)
q[t++] = p[i];
}
sort(q, q + t, cmp1);
for(int i = 0; i < t; i++){
for(int j = i + 1; j < t; j++){
if(q[j].y - q[i].y > res)
break;
res = min(res, solve_dis(q[i], q[j]));
}
}
return res;
}
int main()
{
int n; cin >> n;
for(int i = 0; i < n; i++)
cin >> p[i].x >> p[i].y;
sort(p, p + n, cmp);
double ans = solve(p, 0, n - 1);
cout << "最近点对的距离为:" << ans << endl;
return 0;
}