The Closest M Points bzoj 3053
Posted 草根柴鸡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了The Closest M Points bzoj 3053相关的知识,希望对你有一定的参考价值。
The Closest M Points
【问题描述】
软工学院的课程很讨厌!ZLC同志遇到了一个头疼的问题:在K维空间里面有许多的点,对于某些给定的点,ZLC需要找到和它最近的m个点。
(这里的距离指的是欧几里得距离:D(p, q) = D(q, p) = sqrt((q1 - p1) ^ 2 + (q2 - p2) ^ 2 + (q3 - p3) ^ 2 + ... + (qn - pn) ^ 2)
ZLC要去打Dota,所以就麻烦你帮忙解决一下了……
【输入格式】
第一行,两个非负整数:点数n(1 <= n <= 50000),和维度数k(1 <= k <= 5)。
接下来的n行,每行k个整数,代表一个点的坐标。
接下来一个正整数:给定的询问数量t(1 <= t <= 10000)
下面2*t行:
第一行,k个整数:给定点的坐标
第二行:查询最近的m个点(1 <= m <= 10)
所有坐标的绝对值不超过10000。
有多组数据!
【输出格式】
对于每个询问,输出m+1行:
第一行:"the closest m points are:" m为查询中的m
接下来m行每行代表一个点,按照从近到远排序。
保证方案唯一,下面这种情况不会出现:
2 2
1 1
3 3
1
2 2
1
【样例输入】
3 2
1 1
1 3
3 4
2
2 3
2
2 3
1
【样例输出】
5
0
4
题解:
主要算法:KD树;大根堆;
题意就是求与给定点第一近到第m近的点
用KD树查询
期望答案的计算:与给定点最近且不与给定点在同一块的期望点必定在边界上
开始时先将m个inf加入
那么当查询到的点与给定点的距离小于堆顶与给定点的距离时,就去掉堆顶并加入这个点
最后倒序输出
注意初始化(虽然没写什么初始化,但是要考虑一下的)
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdlib>
5 #include<cstdio>
6 #include<cmath>
7 #include<queue>
8 using namespace std;
9 inline void Scan(int &x)
10 {
11 int o = 1;
12 char c;
13 while((c = getchar()) < ‘0‘ || c > ‘9‘)
14 if(c == ‘-‘) o = -1;
15 x = c - ‘0‘;
16 while((c = getchar()) >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘;
17 x *= o;
18 }
19 const int me = 50233;
20 const int inf = 2147483647;
21 struct dot
22 {
23 int lc, rc;
24 int dis;
25 int v[6], mi[6], ma[6];
26 };
27 dot point;
28 dot c[me];
29 dot tr[me];
30 dot ans[me];
31 struct name
32 {
33 int x;
34 int dis;
35 };
36 inline bool operator < (const name &a, const name &b)
37 {
38 return a.dis < b.dis;
39 }
40 priority_queue <name> sta;
41 int e, n, k, m;
42 inline bool cmp(const dot &a, const dot &b)
43 {
44 return a.v[e] < b.v[e];
45 }
46 inline int Min(const int &x, const int &y)
47 {
48 return (x < y) ? x : y;
49 }
50 inline int Max(const int &x, const int &y)
51 {
52 return (x > y) ? x : y;
53 }
54 inline int Sqr(const int &x)
55 {
56 return x * x;
57 }
58 inline void Update(const int &x)
59 {
60 int l = tr[x].lc, r = tr[x].rc;
61 for(int i = 0; i < k; ++i)
62 {
63 tr[x].mi[i] = tr[x].ma[i] = tr[x].v[i];
64 if(l) tr[x].mi[i] = Min(tr[x].mi[i], tr[l].mi[i]), tr[x].ma[i] = Max(tr[x].ma[i], tr[l].ma[i]);
65 if(r) tr[x].mi[i] = Min(tr[x].mi[i], tr[r].mi[i]), tr[x].ma[i] = Max(tr[x].ma[i], tr[r].ma[i]);
66 }
67 }
68 int Build(const int &l, const int &r, int d)
69 {
70 if(d >= k) d -= k;
71 e = d;
72 int mi = l + r >> 1;
73 nth_element(c + l, c + mi, c + r + 1, cmp);
74 tr[mi] = c[mi];
75 if(l < mi) tr[mi].lc = Build(l, mi - 1, d + 1);
76 if(r > mi) tr[mi].rc = Build(mi + 1, r, d + 1);
77 Update(mi);
78 return mi;
79 }
80 inline int Dis(const int &x)
81 {
82 int sum = 0;
83 for(int i = 0; i < k; ++i)
84 sum += Sqr(tr[x].v[i] - point.v[i]);
85 return sum;
86 }
87 inline int Get(const int &x)
88 {
89 int sum = 0;
90 for(int i = 0; i < k; ++i)
91 {
92 if(point.v[i] < tr[x].mi[i]) sum += Sqr(tr[x].mi[i] - point.v[i]);
93 if(point.v[i] > tr[x].ma[i]) sum += Sqr(point.v[i] - tr[x].ma[i]);
94 }
95 return sum;
96 }
97 void Ask(const int &x)
98 {
99 int dis = Dis(x);
100 if(dis < sta.top().dis)
101 {
102 sta.pop();
103 sta.push((name) {x, dis});
104 }
105 int le = inf, ri = inf;
106 if(tr[x].lc) le = Get(tr[x].lc);
107 if(tr[x].rc) ri = Get(tr[x].rc);
108 if(le < ri)
109 {
110 if(le < sta.top().dis) Ask(tr[x].lc);
111 if(ri < sta.top().dis) Ask(tr[x].rc);
112 }
113 else
114 {
115 if(ri < sta.top().dis) Ask(tr[x].rc);
116 if(le < sta.top().dis) Ask(tr[x].lc);
117 }
118 }
119 int main()
120 {
121 // freopen("d.in", "r", stdin), freopen("d.out", "w", stdout);
122 while(~scanf("%d", &n))
123 {
124 Scan(k);
125 for(int i = 1; i <= n; ++i)
126 for(int j = 0; j < k; ++j)
127 Scan(c[i].v[j]);
128 int root = Build(1, n, 0);
129 int t;
130 Scan(t);
131 while(t--)
132 {
133 for(int i = 0; i < k; ++i) Scan(point.v[i]);
134 Scan(m);
135 for(int i = 1; i <= m; ++i) sta.push((name) {0, inf});
136 Ask(root);
137 for(int i = 1; i <= m; ++i)
138 {
139 ans[i] = tr[sta.top().x];
140 sta.pop();
141 }
142 printf("the closest %d points are:\n", m);
143 for(int i = m; i >= 1; --i)
144 {
145 for(int j = 0; j < k - 1; ++j)
146 printf("%d ", ans[i].v[j]);
147 printf("%d\n", ans[i].v[k - 1]);
148 }
149 }
150 }
151 }
以上是关于The Closest M Points bzoj 3053的主要内容,如果未能解决你的问题,请参考以下文章
The Closest M Points//kd树+优先队列
HDU 4347 - The Closest M Points - [KDTree模板题]
数据结构(KD树):HDU 4347 The Closest M Points