QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2770|回复: 0
打印 上一主题 下一主题

距离最近的点对

[复制链接]
字体大小: 正常 放大
韩冰        

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-4 05:18 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
<>给定n 个点(xi,yi)(1≤i≤n),要求找出其中距离最近的两个点。
! d9 H$ Y8 p9 S) B6 C1 \1 M+ u  E7 p, W: w/ v/ h" o
例14-7 假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。若知道任意两个洞的最小距离,可估计金属断裂的概率。这种最小距离问题实际上也就是距离最近的点对问题。# U* L. `6 B2 l3 e
( h  O4 P$ [) M4 B1 [/ ]7 E
通过检查所有的n(n- 1 ) / 2对点,并计算每一对点的距离,可以找出距离最近的一对点。这种方法所需要的时间为(n2 )。我们称这种方法为直接方法。图1 4 - 1 3中给出了分而治之求解算法的伪代码。该算法对于小的问题采用直接方法求解,而对于大的问题则首先把它划分为两个较小的问题,其中一个问题(称为A)的大小为「n /2ù,另一个问题(称为B)的大小为「n /2ù。初始时,最近的点对可能属于如下三种情形之一: 1) 两点都在A中(即最近的点对落在A中);2) 两点都在B中;3) 一点在A,一点在B。假定根据这三种情况来确定最近点对,则最近点对是所有三种情况中距离最小的一对点。在第一种情况下可对A进行递归求解,而在第二种情况下可对B进行递归求解。6 h5 l8 N, n* d
- d% ]  [6 q0 Z* f$ q
# j$ \5 {3 i; a7 i8 k
if (n较小) {用直接法寻找最近点对# M% g5 S7 r+ }! ^/ p; J
  E0 W4 C8 g1 |6 F/ I3 r
R e t u r n ; }
; X: f8 g; S! S+ _7 g. |
6 U% o+ p: E# Y  r// n较大+ C: G0 p9 i- R# g! M7 F% l* {
/ l: L* \  G/ k* Q
将点集分成大致相等的两个部分A和B+ E7 F; \* S  J3 S# l' A
" c" W+ V  N/ ]
确定A和B中的最近点对
' W% p- ?/ n- J* A. W4 f  G$ Y' o- U4 y3 p! h  e
确定一点在A中、另一点在B中的最近点对
# w0 ]1 f' ~' Z& [% o) _
+ Z9 A$ i$ x. H8 `6 v( X3 n从上面得到的三对点中,找出距离最小的一对点3 j( t4 r' e2 w- ]# a& x; N
* T& F2 w& Q: i* @6 w: e+ \
图14-13 寻找最近的点对# |& b* ~6 M; l% j$ \5 f
7 D7 x. E0 T: K* c+ f1 I" u5 H
. _' |; w" T$ j+ Z/ E
为了确定第三种情况下的最近点对,需要采用一种不同的方法。这种方法取决于点集是如何被划分成A、B的。一个合理的划分方法是从xi(中间值)处划一条垂线,线左边的点属于A,线右边的点属于B。位于垂线上的点可在A和B之间分配,以便满足A、B的大小。
6 A+ I$ c  q0 g. F' y8 B
* q6 M+ E* ^" K. W3 H" z例2-8 考察图14-14a 中从a到n的1 4个点。这些点标绘在图14-14b 中。中点xi = 1,垂线x = 1如图14-14b 中的虚线所示。虚线左边的点(如b, c, h, n, i)属于A,右边的点(如a, e, f, j, k, l) 属于B。d, g, m 落在垂线上,可将其中两个加入A, 另一个加入B,以便A、B中包含相同的点数。假设d ,m加入A,g加入B。
3 M3 p; Y5 x  h6 }' L
3 ]9 s# {, U$ j0 r设是i 的最近点对和B的最近点对中距离较小的一对点。若第三种情况下的最近点对比小。则每一个点距垂线的距离必小于,这样,就可以淘汰那些距垂线距离≥ 的点。图1 4 - 1 5中的虚线是分割线。阴影部分以分割线为中线,宽为2 。边界线及其以外的点均被淘汰掉,只有阴影中的点被保留下来,以便确定是否存在第三类点对(对应于第三种情况)其距离小于。用RA、RB 分别表示A和B中剩下的点。如果存在点对(p,q),p?A, q?B且p, q 的距离小于,则p?RA,q?RB。可以通过每次检查RA 中一个点来寻找这样的点对。假设考察RA 中的p 点,p的y 坐标为p.y,那么只需检查RB 中满足p.y- <q.y<p.y+ 的q 点,看是否存在与p 间距小于的点。在图14-16a 中给出了包含这种q 点的RB 的范围。因此,只需将RB 中位于×2 阴影内的点逐个与p 配对,以判断p 是否是距离小于的第三类点。这个×2 区域被称为是p 的比较区(comparing region)。; F+ J1 [% e  G& g

: r  Q" S! Q- [5 z1 D. H例2-9 考察例2 - 8中的1 4个点。A中的最近点对为(b,h),其距离约为0 . 3 1 6。B中最近点对为(f, j),其距离为0 . 3,因此= 0 . 3。当考察是否存在第三类点时,除d, g, i, l, m 以外的点均被淘汰,因为它们距分割线x= 1的距离≥ 。RA ={d, i, m},RB= {g, l},由于d 和m 的比较区中没有点,只需考察i即可。i 的比较区中仅含点l。计算i 和l的距离,发现它小于,因此(i, l) 是最近的点对。% t( X$ O' J" c/ s. r) S
0 b3 r- ~. D' V( k6 G# K
为了确定一个距离更小的第三类点,RA 中的每个点最多只需和RB 中的6个点比较,如图1 4 - 1 6所示。
% V( W/ q  }2 i7 w1 e3 K( G3 p" z/ o" i& c9 `3 ], S
1. 选择数据结构
/ }2 N5 n% a! U* f1 l; ]- v* n& a; a, `$ s/ y+ M
为了实现图1 4 - 1 3的分而治之算法,需要确定什么是“小问题”以及如何表示点。由于集合中少于两点时不存在最近点对,因此必须保证分解过程不会产生少于两点的点集。如果将少于四点的点集做为“小问题”,就可以避免产生少于两点的点集。
: r; ]% U4 W0 X; c/ c( Q, h- Y
9 g" P9 A- k0 m! m每个点可有三个参数:标号, x 坐标,y 坐标。假设标号为整数,每个点可用P o i n t l类(见程序1 4 - 8)来表示。为了便于按x 坐标对各个点排序,可重载操作符<=。归并排序程序如1 4 -3所示。/ m2 f9 P# D3 v  x/ v

' J) e: h/ _. q  W9 F6 S# T) I6 B3 v程序14-8 点类* T9 g0 y4 H/ E: a$ G6 Z  s

: ?2 ?# M$ Z0 a7 @9 D6 N: f1 {class Point1 {
7 g3 b0 ?5 a. ~2 ?' g  F, J
- V  H: ^) e" X8 Bfriend float dist(const Point1&amp;, const Point1&amp;);
: h  s, s7 `$ V" P6 e  P4 x9 b0 Q' E; P+ l4 S
friend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);
& U/ H! y( `- e4 Y7 t: K! n, u7 R5 z
friend bool closest(Point1 *, int, Point1&amp;, Point1&amp;,float&amp;);
( F! h  W% Y( y3 K3 w
7 N  a' Y, X( Y/ Nfriend void main();# a4 P% T/ l1 T& C3 ]5 N

6 L1 t1 p7 z# r/ V: P9 F; W4 Xp u b l i c :
- }+ ^3 F  X4 B
$ ~$ _4 L& O% rint operator&lt;=(Point1 a) const% Q: |2 S& d8 `4 W
4 b) N! s2 t: X3 i1 _$ ?
{return (x &lt;= a.x);}
; j# a# N5 h% g, P
3 }" j( }6 s- q7 t8 bp r i v a t e :! L# J  N2 m, B; r) U4 O7 v
% y1 V% ^/ A* N6 g
int ID; // 点的编号
2 |& b# X- c3 U! I& @% ~2 F
: |% C: f" q" ?float x, y; // 点坐标3 L# t. N# N$ Q- p

7 m: j8 q. s% m" Z2 o, ~- @} ;
- z. |! b6 Z7 a
! p( Z2 M  g3 Hclass Point2 {
0 s# K. Y3 T4 ]; K! {! g  `. r' e1 }7 `! ^
friend float dist(const Point2&amp;, const Point2&amp;);0 u6 N- [1 q* x0 f! \5 G

$ c9 u% H! d0 ], ?+ Yfriend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);  q/ B9 x& Z. b1 Q, @7 l0 R* i0 Q
, G' }2 }- E! v2 s5 @0 P1 k
friend bool closest(Point1 *, int, Point1&amp;, Point1&amp;, float&amp;);
! J* T! ?3 w3 e& L% _
9 }' L) |, ~& n$ g7 wfriend void main();3 w2 T4 I) J! n( B3 N; B3 |' y

5 j0 ~7 C* S, L/ E& ]p u b l i c :
5 w/ j5 \$ N: X9 i0 F3 V! `3 e* `: a: o! b) y
int operator&lt;=(Point2 a) const
9 I2 W, R1 m2 L# C3 r9 ~/ F+ n$ C5 R8 L. Y# A3 @
{return (y &lt;= a.y);}* }' u/ m' H- N
8 j; T% s7 a/ W
p r i v a t e :
1 @8 N8 ~  \# C
5 O) W2 u9 T4 K5 {/ xint p; // 数组X中相同点的索引
3 ]% s0 i" D3 j7 U6 w
7 Q) I* }5 C1 |5 s4 u2 l1 F, u; V8 Jfloat x, y; // 点坐标( h8 z! m; e8 }  O

; q1 B- ]7 E5 f1 B3 [} ;
9 o' t: {9 r2 J6 p# m3 J/ m
, x: G* Y0 |1 H8 j所输入的n 个点可以用数组X来表示。假设X中的点已按照x 坐标排序,在分割过程中如果当前考察的点是X [l :r],那么首先计算m= (l+r) / 2,X[ l:m]中的点属于A,剩下的点属于B。计算出A和B中的最近点对之后,还需要计算RA 和RB,然后确定是否存在更近的点对,其中一点属于RA,另一点属于RB。如果点已按y 坐标排序,那么可以用一种很简单的方式来测试图1 4 - 1 6。按y 坐标排序的点保存在另一个使用类P o i n t 2 (见程序14-8) 的数组中。注意到在P o i n t 2类中,为了便于y 坐标排序,已重载了操作符<=。成员p 用于指向X中的对应点。9 V7 T# v( U! b0 I' H( `2 }' p

1 D3 y, O7 [( C8 e. R/ d确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数d i s t (见程序1 4 - 9 )来计算点a, b 之间的距离。T可能是P o i n t 1或P o i n t 2,因此d i s t必须是P o i n t 1和P o i n t 2类的友元。% _% |3 Q$ P- ~6 p& H( v, x5 A' a

2 c, N$ \6 M6 J5 P: d程序14-9 计算两点距离
: u; f- }6 w$ @; a
) |- b+ c+ l# otemplate<CLASS T>/ s9 }2 T2 Y" D1 M- D" M: H
) E8 F* ]9 R8 R" F) `9 R
inline float dist(const T&amp; u, const T&amp; v)9 @4 D- S: _% H9 ~' ]$ L8 }
! R# m5 s% d4 w! |) n
{ / /计算点u 和v之间的距离% N7 v7 b4 f+ D4 W/ S: u

# z" a! }" _* \& Y; Q# ~$ w7 Y. n: [float dx = u.x-v. x ;( A/ R( @+ d7 O0 {# n
5 D( g) O9 y2 O# t, S7 Q
float dy = u.y-v. y ;
7 N; b% i7 C$ c) C6 q0 \: s' p! J% J" p( A7 a: T
return sqrt(dx * dx + dy * dy);7 @" x! E5 G( d" \- v0 q: d$ A

% J/ e, @1 [! T}0 T! ]6 _# |- e3 y

  u2 p2 }, K9 }$ O/ ?* O- c$ U2 q如果点的数目少于两个,则函数c l o s e s t (见程序1 4 - 1 0 )返回f a l s e,如果成功时函数返回t r u e。当函数成功时,在参数a 和b 中返回距离最近的两个点,在参数d 中返回距离。代码首先验证至少存在两点,然后使用M e rg e S o r t函数(见程序14-3) 按x 坐标对X中的点排序。接下来把这些点复制到数组Y中并按y 坐标进行排序。排序完成时,对任一个i,有Y [i ] . y≤Y [i+ 1 ] . y,并且Y [i ] .p给出了点i 在X中的位置。上述准备工作做完以后,调用函数close (见程序1 4 - 11 ),该函数实际求解最近点对。
( @$ v' @4 C! n8 M9 X2 r. z$ U
5 p1 a$ w$ A4 e2 w6 {" k程序14-10 预处理及调用c l o s e
2 [) R: p: t: w! L- e' z) V
  l8 W" W& g' [" ?0 q$ n8 g& Tbool closest(Point1 X[], int n, Point1&amp; a, Point1&amp; b, float&amp; d)! r2 k/ b% a9 Z6 E

( M$ [5 @( S+ l6 H{// 在n &gt;= 2 个点中寻找最近点对% V! `2 u2 a0 z# F
, @$ F7 W- m6 ^% G$ Y
// 如果少于2个点,则返回f a l s e& `( `! m3 ]1 y0 ?7 U! D$ y% s

% |' w) @* t! G, N# {8 J' _// 否则,在a 和b中返回距离最近的两个点
5 I7 A. {2 O2 U- q7 T0 u
& y9 u0 G7 t. k2 H9 h. X5 N' Jif (n &lt; 2) return false;3 N' J' K0 ]5 y0 t: j: T' @

4 s/ B( p6 f2 N// 按x坐标排序
4 B- X: r3 ?/ |) J4 k) n
; r& _  P+ j. R+ CM e r g e S o r t ( X , n ) ;! B) X, N8 b5 a5 z2 H9 w, _. u$ w9 P

# s$ @( C! y6 J7 A// 创建一个按y坐标排序的点数组* k6 A4 s8 t: Y5 Z8 F7 D% y3 x  J

1 N8 G& j) J2 t8 x' ~Point2 *Y = new Point2 [n];+ n( B- j5 T# ]+ K3 z. O

. p7 Z7 l6 n5 }- H$ l! e6 bfor (int i = 0; i &lt; n; i++) {; T: r* G7 m; }) G8 b- k4 ~6 E
, ?  g# O% n0 j9 }9 i6 @
// 将点i 从X 复制到Y
- g1 `8 P9 j; x/ A' `, o3 l- e
# ~, \) U/ D1 KY.p = i;
9 {2 `; L+ W6 X1 }7 L; h' C% n, R' G! S% a1 X1 a2 y
Y.x = X.x;
! n$ K+ O+ M, K2 r7 C: A5 i3 ^7 S, c  t0 u7 J6 Q+ U
Y.y = X.y;
! k" F5 {( U8 |! G' r" L7 p* u
; s9 `; O' g7 I. F1 K( B$ c}
3 g- q2 Y! O  d& ^! m' j
) x( F- Y+ w) KM e r g e S o r t ( Y,n); // 按y坐标排序% ?/ E4 U5 C) D4 k0 @

; g2 I. g3 O. f) w8 x$ e// 创建临时数组3 P! X: }  c3 b/ Z3 v- z1 I3 Z1 A6 ^9 A

# Z! B/ @9 i1 \- uPoint2 *Z = new Point2 [n];
* X. m/ M4 n$ n. E6 S
' `7 ~7 g8 t' v! W6 ]+ ]// 寻找最近点对% u# {* @. H' O

) g" _  N9 A7 ^1 f, F+ j9 C3 A& Oc l o s e ( X , Y, Z , 0 , n - 1 , a , b , d ) ;
/ e1 j$ V6 J- B( [2 {. ?
" U9 t, \1 s  Y9 C" o; T// 删除数组并返回
9 i3 K( M, I+ P( `" f1 O: E" g' t6 @1 p- v
delete [] Y;2 l9 L2 ^9 m# e7 I. _& I- Q6 g

; V* g( q4 J$ Ndelete [] Z;( f5 X* I0 [# C* \3 h

6 B+ k8 {6 P1 b# }6 U& Z$ k( Lreturn true;
9 _& r6 _; N3 m* i3 d* H2 q6 {3 g* E
}+ x1 T, R) h! i' P$ X

3 @* C) T) T0 [程序1 4 - 11 计算最近点对
: h& P9 n$ u, ?2 N7 x6 _: F
( O. S/ B9 w( ?/ S6 avoid close(Point1 X[], Point2 Y[], Point2 Z[], int l, int r, Point1&amp; a, Point1&amp; b, float&amp; d)
- ~' x+ ^/ u  f& m! \; e- R0 O9 h5 s1 J7 }  U$ N1 B3 J2 a: Q
{//X[l:r] 按x坐标排序' b. b- u% w% D& D, S  K- l

1 {# u/ }) z6 q2 [5 \: Y//Y[l:r] 按y坐标排序4 l8 W: o( P& S$ t/ E% I/ \1 h
1 z' `5 N5 q8 j7 e' t( }2 Y
if (r-l == 1) {// 两个点
- e7 ~9 [3 r2 b* }+ ]' T
8 V- i1 G# W5 J( m' u$ K9 e% a: aa = X[l];2 m! h. m0 R2 i% D3 u1 L
1 B1 Y1 s0 {: N' R. I
b = X[r];
8 I3 N! u! N. I$ l4 i3 I
: u$ Q  b# K; f# @d = dist(X[l], X[r]);
  f( H- r  m$ W: q1 ~, s$ f8 j
& T8 F( z6 M5 m5 I1 [/ [r e t u r n ; }
  R6 |. \: {2 p2 ^9 j) d% P1 G0 G3 G" L& j2 \
if (r-l == 2) {// 三个点+ ^. @& X9 T5 b6 ^0 w

* }; V: d' |4 y& W' c' Y' i; L/ z& R// 计算所有点对之间的距离
7 E5 s* i4 l7 E" ~6 x& e- A  W
7 J/ x  c4 v# x9 @3 u& u: Lfloat d1 = dist(X[l], X[l+1]);
! _9 n! j6 d' B: `& i
5 Y. A2 F* {7 g  R  m; o+ L% Z: kfloat d2 = dist(X[l+1], X[r]);
& s! Y* @, \7 P6 P7 ]! S) w5 j& Y* n0 q: x
float d3 = dist(X[l], X[r]);
& D3 M8 r% c2 N+ [5 w( m
# g3 b3 l) ^- i% W// 寻找最近点对
' z; l; I; l. A( J; @: L
/ u6 T8 Q8 V, z: X/ L2 Dif (d1 &lt;= d2 &amp;&amp; d1 &lt;= d3) {& n+ C- p; m8 Z3 S  G; r

8 y0 f4 `# I; g: N, H/ Xa = X[l];& r- y" G+ Q6 V: l9 g' l7 T
2 Y( ?. k2 }2 w$ Q$ S2 n
b = X[l+1];' K; _: i! c7 f" r

/ r6 c9 @) v2 q6 R$ l7 X: R7 Yd = d1;. u/ z1 d+ f7 M; z/ J% |1 b
4 W% P  K$ P. r" n! L
r e t u r n ; }! Y- Y" [# J+ x" Z
  ^0 R: U% k* }' g' Y& T
if (d2 &lt;= d3) {a = X[l+1];3 \, |( o! t' c1 i" m7 p2 Y

/ R- a1 Z1 Q/ a, h& f: |# F1 V9 mb = X[r];
) ?% w' P5 e" p& W: g5 n1 F9 _9 E% _' w& G
d = d2;}/ q0 I. |& C. V

5 @/ ~% @9 X/ u: |else {a = X[l];3 j- c3 i) A0 k4 c: G: i

9 j! z1 \1 K4 {0 k* v  v& [- ob = X[r];
9 }# X7 E- `5 j8 ^1 j! c
* x. S- p, N9 j+ s' g- md = d3;}
( u" p1 s: q& K* o6 b& K
6 q! ]( d/ O0 G# Ir e t u r n ; }1 J) Q' m( L; h' ^$ J6 o
( @  h% |2 D3 F! W, ^
/ /多于三个点,划分为两部分
" U% k/ Q) S. g
3 T) M  j, A' k. @- Yint m = (l+r)/2; // X[l:m] 在A中,余下的在B中* p* L: k1 D  G& X

' a5 `# g, v7 z* n1 X// 在Z[l:m] 和Z [ m + 1 : r ]中创建按y排序的表1 j! ^8 h4 y4 K
: G& c; U1 o, N6 V  ^( `3 X. Y
int f = l, // Z[l:m]的游标$ O/ {$ b" s7 O$ \) N5 d  \

- Q! ^, D* [4 Q; L! y. j) Mg = m+1; // Z[m+1:r]的游标) ]) b% `  j+ z; x: I6 \' f

' t6 `5 L- f0 p, S: }! M" l; L1 R' Ffor (int i = l; i &lt;= r; i++)
; t1 c* V1 L' R2 s  T9 a& G7 w, w
if (Y.p &gt; m) Z[g++] = Y;% ]' b8 t0 _& L5 f' i
' I* U+ ~  ~- O; a, n1 B
else Z[f++] = Y;' V0 H2 T; @: ^
) t6 ]& ]7 @  J- n$ L
// 对以上两个部分进行求解
1 w) t9 [, K" [5 c( K
+ e. I% Y$ Y! S" yc l o s e ( X , Z , Y, l , m , a , b , d ) ;
9 Y- G. {- h& ?' q" Y' w
0 r4 L! I% U# V6 [& h. Tfloat dr;
9 z1 v  v  O, K" l* W1 \8 n' b9 p( P9 B; n* r7 m5 j
Point1 ar, br;0 [) ^$ r' q# `0 b
4 F! i6 _: l) i6 o
c l o s e ( X , Z , Y, m + 1 , r, a r, b r, d r ) ;
0 x: K! A& W# `; _' G  K0 y7 H( x; v0 F# u7 l/ n$ l
// (a,b) 是两者中较近的点对
2 F* v" z! o) j' h# X7 [; i$ \& H8 B" g
if (dr &lt; d) {a = ar;/ z. Q& a$ m/ ]* o: [

+ I, H' U7 x; ]* {9 ib = br;
' y7 E  f* {& }. `9 `
& ]# k. Y% N% B+ w# Dd = dr;}+ Y8 |$ X# I3 K3 a

" T9 h1 @  s- c3 {6 nM e r g e ( Z , Y,l,m,r);// 重构Y5 _2 K/ Q, f/ u8 w7 }' Z

$ u, C  f" O5 ]/ /距离小于d的点放入Z
  o# p) T4 a$ N# m  i
% P: a; v# D) v. P' fint k = l; // Z的游标1 z2 g6 K" C" L/ {) w/ m% l* w
- G& s! y! v; M7 B  |6 Z% U
for (i = l; i &lt;= r; i++)
0 k$ T/ ^! F4 l$ M, [6 c  e! m
+ Q# J) n$ Z( `) \* Xif (fabs(Y[m].x - Y.x) &lt; d) Z[k++] = Y;5 D" h* N% h; `1 g  T7 k
- r& a& k8 C  }* }( T
// 通过检查Z [ l : k - 1 ]中的所有点对,寻找较近的点对) Z8 W* |# p- T- n: ]1 e8 k
3 d1 B+ f6 |2 u
for (i = l; i &lt; k; i++){! e) W6 x& v# u" {
0 R3 t7 a8 A* f" e. r" M
for (int j = i+1; j &lt; k &amp;&amp; Z[j].y - Z.y &lt; d;
/ V$ C" a  `) N1 m5 a% }6 d3 h+ J% g3 e3 o7 o
j + + ) {: D7 U" b( p" L* g/ O" R

3 Q. h5 G: E  ]/ b' W7 pfloat dp = dist(Z, Z[j]);
- Q0 Z3 i8 v/ n
& @( `" V0 d5 r% _% H: `if (dp &lt; d) {// 较近的点对1 P3 l% j# l% q! P
' ?) q0 K- l1 A9 W3 ?+ ~
d = dp;$ M) b; y: v3 b& |

! @3 M( F/ A. ~% C; D9 Ka = X[Z.p];4 y$ N+ W. A' c; j' p2 q
8 i: ?+ M5 ^4 |/ f7 v
b = X[Z[j].p];}. J+ X4 `& p* c  w
+ p& W( @. t- ^! t( U0 [
}$ r% U# Q4 F% H* r5 D0 ^1 v+ ~
! [3 `  f* z; |( ^" t0 a
}
8 ]- ]* B) X8 g! |# V4 S
  p8 f! C. a  J  x: a6 m" s, ]}3 K; I( t' @( I! B8 r8 b  G0 D- p

) P. J- X/ k. ]) _$ z3 E函数c l o s e(见程序1 4 - 11)用来确定X[1:r] 中的最近点对。假定这些点按x 坐标排序。在Y [ 1 : r ]中对这些点按y 坐标排序。Z[ 1 : r ]用来存放中间结果。找到最近点对以后,将在a, b中返回最近点对,在d 中返回距离,数组Y被恢复为输入状态。函数并未修改数组X。* S* S, p. b& r) K

8 G3 j6 J( g9 u9 X6 H$ e首先考察“小问题”,即少于四个点的点集。因为分割过程不会产生少于两点的数组,因此只需要处理两点和三点的情形。对于这两种情形,可以尝试所有的可能性。当点数超过三个时,通过计算m = ( 1 + r ) / 2把点集分为两组A和B,X [ 1 : m ]属于A,X [ m + 1 : r ]属于B。通过从左至右扫描Y中的点以及确定哪些点属于A,哪些点属于B,可以创建分别与A组和B组对应的,按y 坐标排序的Z [ 1 : m ]和Z [ m + 1 : r ]。此时Y和Z的角色互相交换,依次执行两个递归调用来获取A和B中的最近点对。在两次递归调用返回后,必须保证Z不发生改变,但对Y则无此要求。不过,仅Y [ l : r ]可能会发生改变。通过合并操作(见程序1 4 - 5)可以以Z [ 1 : r ]重构Y [ 1 : r ]。' i) o; ~0 E2 g1 s& ~6 x

1 @: H7 E8 U, V% ~4 z为实现图1 4 - 1 6的策略,首先扫描Y [ 1 : r ],并收集距分割线小于的点,将这些点存放在Z [ 1 : k - 1 ]中。可按如下两种方式来把RA中点p 与p 的比较区内的所有点进行配对:1) 与RB 中y 坐标≥p.y 的点配对;2) 与y 坐标≤p.y 的点配对。这可以通过将每个点Z [ i ](1≤i &lt; k,不管该点是在RA
$ A, p7 N. W0 z6 i  k
; d2 m. G' f, X: T2 I, z# s0 C3 }还是在RB中)与Z[j] 配对来实现,其中i<j 且Z [ j ] . y - Z [ i ] . y< 。对每一个Z [ i ],在2 × 区域内所检查的点如图1 4 - 1 7所示。由于在每个2 × 子区域内的点至少相距。因此每一个子区域中的点数不会超过四个,所以与Z [ i ]配对的点Z [ j ]最多有七个。
. F& k) u. h$ Q
/ q9 h; g& |' m! K- \1 P2 a" g2. 复杂性分析
8 P: y; q& E8 ?# S; n. v& Y7 A/ X) _& x8 E+ z0 a. Y' [9 V
令t (n) 代表处理n 个点时,函数close 所需要的时间。当n<4时,t (n) 等于某个常数d。当n≥4时,需花费(n) 时间来完成以下工作:将点集划分为两个部分,两次递归调用后重构Y,淘汰距分割线很远的点,寻找更好的第三类点对。两次递归调用需分别耗时t (「n /2ù」和t (?n /2?).7 u% t3 s8 N/ l2 K' a

4 |8 g' ~) f1 x! V: d  J这个递归式与归并排序的递归式完全一样,其结果为t (n) = (nl o gn)。另外,函数c l o s e s t还需耗时(nl o gn)来完成如下额外工作:对X进行排序,创建Y和Z,对Y进行排序。因此分而治之最近点对求解算法的时间复杂性为(nl o gn)。</P>
zan
转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
您需要登录后才可以回帖 登录 | 注册地址

qq
收缩
  • 电话咨询

  • 04714969085
fastpost

关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

手机版|Archiver| |繁體中文 手机客户端  

蒙公网安备 15010502000194号

Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

GMT+8, 2026-4-21 04:06 , Processed in 0.313656 second(s), 51 queries .

回顶部