题解 洛谷 P1257/P1429/P7883 平面最近点对
本文主要介绍分治法
P1257
因为数据范围太小从而可以
P1429/P7883
这两道题的数据范围都在
分治策略
考虑将这些点划分成若干区间进行比较,因为点是乱序的,所以我们先对所有点按照
1.两个点都在
2.两个点都在
3.一个在左边,一个在右边
诶!我们发现这种对比方式是不是在哪里见过呀,没错,就是逆序对!那么这个题可以说和逆序对没有什么关系。但是我们在分治的时候采取的策略是有相似之处的,前两种情况只需要用最普通的递归就可以轻松解决,像这样:
1
dis = min(solve(l,mid), solve(mid + 1, r));
将这些点取出来以后,我们先对这些点按照
于是这道题就做完了,下面是1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using namespace std;
namespace SHAWN {
const int N = 2e5 + 7;
const LD INF = 1e18;
struct node { LD x, y; }pt[N];
int que[N];
int n;
bool cmp1 (node a, node b) { return a.x < b.x; }
bool cmp2 (int a, int b) { return pt[a].y < pt[b].y; }
LD getlen(node a, node b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); }
LD solve(int l, int r) {
if (l == r) { return INF; }
if (l == r - 1) { return getlen(pt[l], pt[r]); }
int mid = l + ((r - l) >> 1);
LD dis = min(solve(l, mid), solve(mid + 1, r));
int idx = 0;
for (int i = l; i <= r; ++i) {
if ((pt[mid].x - pt[i].x) * (pt[mid].x - pt[i].x) < dis) {
que[++idx] = i;
}
}
sort(que + 1, que + idx + 1, cmp2);
for (int i = 1; i <= idx; ++i) {
for (int j = i + 1; j <= idx && ((pt[que[i]].y - pt[que[j]].y) * (pt[que[i]].y - pt[que[j]].y)) < dis; ++j) {
dis = min(dis, getlen(pt[que[i]], pt[que[j]]));
}
}
return dis;
}
int work()
{
cin >> n;
for (int i = 1; i <= n; ++i) { cin >> pt[i].x >> pt[i].y; }
sort(pt + 1, pt + n + 1, cmp1);
cout << fixed << setprecision(4) << sqrt(solve(1, n)) << '\n';
return 0;
}
}
signed int main() {
ios :: sync_with_stdio(false);
cin.tie(nullptr);
return SHAWN :: work();
}