最近点对问题学习笔记

最近点对问题,就是在一个点集中找到最近的一对点的距离。

先看一道例题

AcWing119

在题解的帮助下,我终于A了此题。

题目大意就是有n个特工和n个核电站,求最近的任意一个特工到任意一个核电站的距离。

首先我们只要将点分为两组,同组的点之间距离为无穷大,就可以将本题转换为最近点对问题。

最近点对问题如何解呢?

第一时间想到的是n2的暴力,但无疑是要超时的。

于是我们需要用分治来优化一下。

首先在一般情况下,最近两个点的横坐标的差是较小的,我们可以对于横坐标进行分治。

 

扫描二维码关注公众号,回复: 8414480 查看本文章

如图,以横坐标为第一关键字排序后,将所有点分成两部分(至于中间那个随便分到哪块)。

很显然最短距离是在左块的最短距离和右块的最短距离,当然也可能不同块的点的距离,比如说图中的ab。

前两种都是非常方便实现的,只需要不断分治就好。麻烦的是第三种情况。

我们可以先将前两种的最小值ans求出,以横坐标和中间点差小于等于ans的才可能是第三种情况。

于是我们只需要求这些点之中最短距离。

对于这些点我们可以直接用暴力做,一般情况下应该不会很大。

当然,如果纵坐标的距离大于ans,也是不可能是最短距离的。

    	sort(b + 1, b + cnt + 1, cmp2);
	rep(i, 1, cnt)
		rep(j, i + 1, cnt){
			if(b[j].y >= b[i].y + ans) break;
			ans = min(ans, dist(b[i], b[j]));
		}

 可以将纵坐标为第一关键字排序,进行剪枝。

放上我错了好几次的代码

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <vector>
 7 #define rep(x, l, r) for(int x = l; x <= r; x++)
 8 #define repd(x, r, l) for(int x = r; x >= l; x--)
 9 #define clr(x, y) memset(x, y, sizeof(x))
10 #define all(x) x.begin(), x.end()
11 #define pb push_back
12 #define mp make_pair
13 #define MAXN 200005
14 #define fi first
15 #define se second
16 #define SZ(x) ((int)x.size())
17 using namespace std;
18 typedef long long ll;
19 typedef vector<int> vi;
20 typedef pair<int, int> pii;
21 const int INF = 1 << 30;
22 const int p = 1000000009;
23 int lowbit(int x){ return x & (-x);}
24 int fast_power(int a, int b){ int x; for(x = 1; b; b >>= 1){ if(b & 1) x = 1ll * x * a % p; a = 1ll * a * a % p;} return x % p;}
25 
26 int n;
27 struct node{
28     double x, y;
29     bool col;
30 }a[MAXN], b[MAXN];
31 
32 bool cmp1(node a, node b){
33     if(a.x == b.x) return a.y < b.y;
34     return a.x < b.x;
35 }
36 
37 bool cmp2(node a, node b){
38     if(a.y == b.y) return a.x < b.x;
39     return a.y < b.y;
40 }
41 
42 double dist(node a, node b){
43     if(a.col == b.col) return INF;
44     return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
45 }
46 
47 double work(int l, int r){
48     if(l == r) return INF;
49     if(l == r - 1) return dist(a[l], a[r]);
50     int mid = (l + r) >> 1;
51     double ans = min(work(l, mid), work(mid + 1, r));
52     int cnt = 0;
53     rep(i, l, r)
54         if(a[i].x >= a[mid].x - ans && a[i].x <= a[mid].x + ans) b[++cnt] = a[i];
55     sort(b + 1, b + cnt + 1, cmp2);
56     rep(i, 1, cnt)
57         rep(j, i + 1, cnt){
58             if(b[j].y >= b[i].y + ans) break;
59             ans = min(ans, dist(b[i], b[j]));
60         }
61     return ans;
62 }
63 
64 int main(){
65     int t;
66     scanf("%d", &t);
67     while(t--){
68         scanf("%d", &n);
69         rep(i, 1, n){
70             scanf("%lf%lf", &a[i].x, &a[i].y);
71             a[i].col = 0;
72         }
73         rep(i, n + 1, 2 * n){
74             scanf("%lf%lf", &a[i].x, &a[i].y);
75             a[i].col = 1;
76         }
77         n *= 2;
78         sort(a + 1, a + n + 1, cmp1);
79         double ans = work(1, n);
80         printf("%.3f\n", ans);
81     }
82     return 0;
83 }
View Code

猜你喜欢

转载自www.cnblogs.com/nblyz2003/p/12147898.html