QQ登录

只需要一步,快速开始

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

距离最近的点对

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-4 05:18 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
<>给定n 个点(xi,yi)(1≤i≤n),要求找出其中距离最近的两个点。9 q2 Y6 F) |( t  x
8 v8 x  J! @. M6 l$ u
例14-7 假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。若知道任意两个洞的最小距离,可估计金属断裂的概率。这种最小距离问题实际上也就是距离最近的点对问题。
, {2 [/ Q0 J% h1 C: i2 g2 {) l7 W; o9 y- M/ V8 `! u
通过检查所有的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进行递归求解。4 E# P+ U2 a; ?* V* Q
! f1 u% O1 h/ K

; V$ E) `, o8 ?4 X% yif (n较小) {用直接法寻找最近点对2 Q5 m. t7 Q) n/ y7 r# s; x
  c; h7 o! J+ q+ x
R e t u r n ; }+ L7 e! J7 u+ a

3 m' s% [% R3 F. X: e// n较大' D# ]1 R8 d7 D- b" ?" S) J- O7 i
5 o1 Z+ W: M! C, C8 h
将点集分成大致相等的两个部分A和B
( v; @% \  l  n6 D2 K6 c* N3 y8 ], E( C( |' h
确定A和B中的最近点对
0 @" i5 T! K; w# R8 w/ P: c3 C7 G8 l$ h+ I6 Q3 A0 T% e) `
确定一点在A中、另一点在B中的最近点对
% z: z, A* a: W/ B
( e  W! j. Q5 y9 [' F9 l6 ]从上面得到的三对点中,找出距离最小的一对点7 ~4 G, ^: t4 Z/ d+ b' h* E$ _# ^

; G7 F+ B- |* F- _" @6 R5 N. }, w图14-13 寻找最近的点对. T2 A9 W, a/ H4 o- j; @
, N6 N0 y6 _; d

1 l+ M; p+ S( q. M. ^. j7 H: G# f; s为了确定第三种情况下的最近点对,需要采用一种不同的方法。这种方法取决于点集是如何被划分成A、B的。一个合理的划分方法是从xi(中间值)处划一条垂线,线左边的点属于A,线右边的点属于B。位于垂线上的点可在A和B之间分配,以便满足A、B的大小。
9 C6 y' T8 `3 J/ [
0 C1 C& \) d# s8 D! L# {9 j例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。
" n3 ?: x& b, M5 `* ]2 m3 h2 _# k: ~- b9 v! n0 u+ E
设是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)。1 n: K  B/ O+ C
/ G+ Q5 W% i  t& \' h9 N) ~( j& I8 L
例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) 是最近的点对。& m2 i8 `  @7 {( @% \/ d

7 x2 V5 U3 M$ B1 l; z为了确定一个距离更小的第三类点,RA 中的每个点最多只需和RB 中的6个点比较,如图1 4 - 1 6所示。
) V8 v9 `% ~, v4 O1 {( j7 s
8 e, ~) w( I8 F2 H1. 选择数据结构2 g$ a4 ~: n) w( y% d4 Z6 D6 K

" u4 i) J7 c" W# s为了实现图1 4 - 1 3的分而治之算法,需要确定什么是“小问题”以及如何表示点。由于集合中少于两点时不存在最近点对,因此必须保证分解过程不会产生少于两点的点集。如果将少于四点的点集做为“小问题”,就可以避免产生少于两点的点集。. w6 D1 f" H% G' E5 }% T
! M1 t& q9 w2 S' Z6 J
每个点可有三个参数:标号, x 坐标,y 坐标。假设标号为整数,每个点可用P o i n t l类(见程序1 4 - 8)来表示。为了便于按x 坐标对各个点排序,可重载操作符<=。归并排序程序如1 4 -3所示。) w( W; ]9 s5 a4 o4 D& B2 }

0 ?  E; z' P- \# Z' U1 r0 y程序14-8 点类
$ B$ u- v, y  N& \0 i, ~& v- D' x- s
class Point1 {
4 I" m1 Y$ @7 w: s
  @" }& x4 O3 e5 d4 T$ V+ J/ \friend float dist(const Point1&amp;, const Point1&amp;);) I5 y; }& N8 a4 P+ }9 D
/ `$ w' }/ ^$ B- C3 \2 H; F
friend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);! t4 M; f1 P# i" ?6 n# f5 A! G2 @

) D- p" N7 m1 k# zfriend bool closest(Point1 *, int, Point1&amp;, Point1&amp;,float&amp;);
7 i& n1 r1 w1 l) I: {7 a7 ^1 }4 T$ \% r# X) M
friend void main();  o) ~8 h" P. j' n
0 Q1 [  Q+ E  n+ O( ^1 W! d- M
p u b l i c :
+ m* u* C: n& X8 i5 U! x/ E" }+ k& u3 P/ b% M) S% I
int operator&lt;=(Point1 a) const& E1 D0 P5 W% w& O

2 ~7 D: K& F5 L: x- p{return (x &lt;= a.x);}+ x1 d) t2 A' w! B) }
2 K: o. o' b& R1 N/ P& {
p r i v a t e :2 Q3 p  C9 B9 k7 h0 H
7 ?( E) C" i/ b& m6 y$ Z% k
int ID; // 点的编号; `( V0 j5 z, ^
1 }; D5 I# |0 @8 k2 i% \6 u) H
float x, y; // 点坐标
, y7 z& h7 l4 q7 O0 P. X" O
# w0 v' Z0 J# W} ;4 d: q& {4 K; r: F( T
* m+ z! Q5 t& D1 N
class Point2 {5 }3 l" z. P+ j* U7 g+ X5 ^
- J# M7 c* c2 F$ P2 ]
friend float dist(const Point2&amp;, const Point2&amp;);: e6 c3 j4 W% \- \2 }& a

. \. k' c, D( \friend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);
5 G- W) M" W; j% i+ d# x% M$ w
, M4 Z2 {- E5 ?( r, O5 jfriend bool closest(Point1 *, int, Point1&amp;, Point1&amp;, float&amp;);
6 I* |7 E% \% A8 _- F: v8 a' B1 j, x( m- y/ O  d) {0 \8 O# ?
friend void main();% l/ P+ g9 k5 o  C8 E/ u) R& l! |

8 k0 C( b- g2 ~p u b l i c :
7 u$ _) E! R7 k: S9 Y6 N- A
% Q8 u/ h0 T% h4 Q5 ?* ~3 xint operator&lt;=(Point2 a) const
0 O5 S, l4 ^- o5 m( J. I4 R
+ j: U- Y1 f! K4 T5 B9 ^{return (y &lt;= a.y);}. B, ?! L& @9 X; f3 ~5 Q
" `/ y$ I5 F& P0 c( G/ O( _
p r i v a t e :
5 r, e/ j- {( O$ p
* \: s3 m3 c: e* O# Jint p; // 数组X中相同点的索引2 |; E" M8 R$ }

' E. ^/ v. n  Vfloat x, y; // 点坐标
) L7 \7 P% q1 J- K* y6 S* ^* u+ X3 }0 T; E9 V1 R5 @
} ;
8 i# m6 M5 |9 J8 \  k
  x# ]8 U; F! B4 g/ F: k; r所输入的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中的对应点。: J) S# J# L3 `3 I9 \' G; }: t
% @" e6 z& L3 X* y+ m
确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数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类的友元。
9 l% O" O9 n  p- P- W  w- H$ M: C5 ~
程序14-9 计算两点距离
! L2 _4 C1 p( y5 i9 F4 k+ y% r4 _, t3 u7 [
template<CLASS T>
) q, B  U8 a: g( a' q7 X2 y. e6 M8 O, [! z: _, k7 ^
inline float dist(const T&amp; u, const T&amp; v)8 m9 g+ k: K( ^8 L! W2 e
( a; R7 C- |, \1 A1 A1 Z
{ / /计算点u 和v之间的距离
2 L' h& T7 A& z7 a# Y/ k2 A& J. k2 P, K
float dx = u.x-v. x ;5 b6 I2 o: \* m* w& d" g: N8 @/ w
/ I' x- p7 }4 ~( T& b! n2 x9 G, N$ G
float dy = u.y-v. y ;0 H( V4 l: o2 K" f/ m5 T! F
; @* l) j/ @4 ]
return sqrt(dx * dx + dy * dy);
; [; ?3 i$ y2 M3 y( o0 h8 h! e
! e2 E9 M" ?1 O# l- \) @+ S}
! V; A; [# r) o9 `) i
7 p3 H% w/ A- A2 o如果点的数目少于两个,则函数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 ),该函数实际求解最近点对。
9 {+ P& N+ s, m) Z! ^* [. w
, I  [! P4 c# [8 ?2 s# a" u程序14-10 预处理及调用c l o s e
5 L$ k% M* ^" i5 m, p& J# P  K# F3 d
bool closest(Point1 X[], int n, Point1&amp; a, Point1&amp; b, float&amp; d)! k5 J' }! W1 k( Q) D# X

$ u. L: y) c+ `6 H9 |& c% }0 V( k* t{// 在n &gt;= 2 个点中寻找最近点对# W. q' V* r3 |7 S! ]# }' N
2 g" `. q: |. Y! t0 J, I' B/ ?/ _' t
// 如果少于2个点,则返回f a l s e6 b8 s' c: q! F7 Q

7 y! i1 ]9 k& ~- S8 h& ]3 n// 否则,在a 和b中返回距离最近的两个点
1 @! d7 U$ n/ q1 _& Q# Z; w6 g0 V4 J+ A3 W
if (n &lt; 2) return false;
8 x' {7 y1 J4 s' J! F- r6 [  N$ D5 O' T! n5 B% T
// 按x坐标排序* i/ M/ D: F, j- {' V- d: s
4 W8 v" C$ }0 D8 l5 L
M e r g e S o r t ( X , n ) ;8 p8 W  z' `6 ^

# {! t' w$ I" s. Q// 创建一个按y坐标排序的点数组
  N6 ^% c. B4 ^  L( S% t, ~
+ r% U8 U4 y" }1 g4 f; k$ `6 _/ oPoint2 *Y = new Point2 [n];
& d/ k$ Y+ B( [% o/ T. h. q8 \! J" w- Z0 S  D4 {5 X+ u4 j  t% ^; C
for (int i = 0; i &lt; n; i++) {
4 I; O8 e  r4 w0 C; \" ]
3 h4 \1 D, g6 F8 u// 将点i 从X 复制到Y
' G9 B, i9 _: l' H
% s( E  `& r( z# K2 N8 I5 rY.p = i;/ w; w/ H3 I9 Z+ _
7 W  G  p5 h) h$ n. p4 Y7 L' F
Y.x = X.x;
% ^* K0 [- N% y" w& O* x
0 ~: F, k0 _8 Q" [; S% J, a7 m5 n! z6 HY.y = X.y;5 Z4 s$ ]" ?, h7 i/ t

9 ?8 p6 j8 U. A/ n  J7 F+ g3 t3 }}) ~& \( T8 A7 J' g4 C3 I3 P+ i

0 ]+ g* F9 y7 n- A2 V& iM e r g e S o r t ( Y,n); // 按y坐标排序
" N* r' W' Q3 s: [3 H2 x* ~0 [/ i, M7 J, Z' A( O
// 创建临时数组
: U6 G( a3 J2 z) K
' b, k6 L5 ^8 f* I1 OPoint2 *Z = new Point2 [n];' s  ?" I: H5 m$ d% }

5 M" ^7 F% d. o- X8 T4 y: x7 ?" o- Z// 寻找最近点对* ?' V5 `7 ?6 y. n
& Z$ v5 U- n) @) Z2 C; A* R: V9 b
c l o s e ( X , Y, Z , 0 , n - 1 , a , b , d ) ;% W: e" o3 O6 p% ]. b1 C& E
. W6 r* E4 G; [$ L+ J
// 删除数组并返回
# ?0 I' B9 M; D4 b/ I
  m$ S' l; B: v: Mdelete [] Y;
( L- m" c$ J. Y4 H' x( u/ j3 l  K7 U/ T0 h0 P8 z  y$ x
delete [] Z;% O1 z+ Y  F+ N5 S- {8 L5 m8 |4 a
" b9 p! d: Y  \, X
return true;* z8 L- X, O% P- j) H6 w& D  P

- E6 F/ ^. u1 B- s) h1 R6 r}
& A; M+ R& `4 C1 U; K' H. }
. \, l6 X7 Y' r程序1 4 - 11 计算最近点对7 ~) X$ @0 ?' \' E! B
9 V' _" l, F& o- _( a
void close(Point1 X[], Point2 Y[], Point2 Z[], int l, int r, Point1&amp; a, Point1&amp; b, float&amp; d)
5 m  w0 V* p7 l, G. {, n) J5 U$ l2 [0 ?$ F  G4 ?$ t' G% F0 ~4 F5 V
{//X[l:r] 按x坐标排序
/ g- d( w3 H" }2 a  A, s9 k; ]7 w, u, F
//Y[l:r] 按y坐标排序( B, O2 L8 m" x3 ~( D" n- @- R
% Z) |, q- a2 H; M, m" }
if (r-l == 1) {// 两个点0 s( B: D5 n8 X7 G! l0 V

( O" ~  @, \/ v; ]  W8 ga = X[l];* f( u3 s8 I, V" Z% f

, \' Z6 T  o5 m# P4 P0 ?% ?b = X[r];
5 n' B3 [6 E) L+ d0 {9 W& q& ?% Y* @
d = dist(X[l], X[r]);' q  v+ q$ e7 ^% I& ]9 A

6 H( s7 G% [/ i2 Rr e t u r n ; }
+ L, w: N0 F7 l  V. N9 e9 W! x
+ H5 }1 g- c3 q& w1 g0 M4 Tif (r-l == 2) {// 三个点
% y- d+ z; H7 j
8 H6 _* O' _4 H. J* V// 计算所有点对之间的距离# ~: \; W# B* R9 K  S5 q& U. V0 A% |

; {5 H1 Q6 I3 p0 E! Mfloat d1 = dist(X[l], X[l+1]);+ m; r& F9 H1 ?& N8 o- Z( a

3 b$ ]/ h' D8 S: ]$ B; L6 F- R! wfloat d2 = dist(X[l+1], X[r]);
) _- J9 B" \; e( y, o: o) c# o  s/ v; t& ~2 W: i
float d3 = dist(X[l], X[r]);# |  h$ T5 D9 B" f: y5 Q+ x$ m
6 G8 h6 x3 t1 m# e
// 寻找最近点对- @$ L2 |/ g8 f; k7 x

4 w, B6 h" l6 O% fif (d1 &lt;= d2 &amp;&amp; d1 &lt;= d3) {
4 z- R  |5 ?5 H- R' N, o4 f/ U" l, q3 H5 w) W
a = X[l];
; S- \# I; X0 U2 l0 B0 k# t2 ]1 g/ e
b = X[l+1];
/ I/ H, ^$ L# g/ \7 V5 Y/ m; X8 `8 \
d = d1;5 F& j9 ]& x. c

2 ^5 P6 y! l! O/ t; l7 Y% w0 Er e t u r n ; }  h. V# M. t) I! t2 Z, Q8 s
* A+ u; T+ |$ G5 ?& p( Z
if (d2 &lt;= d3) {a = X[l+1];. }. ?6 y2 I9 K) i  ~

/ A5 d" r  n4 xb = X[r];$ c& |& b6 T" K, @

% a. w# t& h( z& i  Dd = d2;}1 d# `9 B9 y+ W# y, q
9 @9 e0 D, c- T5 i9 e# ~
else {a = X[l];
1 ]( w& S+ d% c3 b+ |$ ^: a" y+ i+ d$ w. S
b = X[r];  w2 K) y* h8 U4 J* E" P; v1 A

# S+ B4 r6 b5 od = d3;}3 s- K: a, v# t  G) h" {

$ N! W5 s  [; v7 I3 qr e t u r n ; }- r6 ^* N8 f+ z
( o7 m/ J: ~2 ?$ C, S- b
/ /多于三个点,划分为两部分
. m! @4 Z4 {1 d: B. w- v( p, C3 E. H4 j
int m = (l+r)/2; // X[l:m] 在A中,余下的在B中
9 W$ x- o* M( H: H& B+ P* I9 y9 w5 O# d' d) J" W
// 在Z[l:m] 和Z [ m + 1 : r ]中创建按y排序的表9 r% r5 ^2 [( p

" k  O9 z2 B0 ^. \( X1 n- b! e6 W. q* h) h+ Wint f = l, // Z[l:m]的游标
  s  L+ ~! X0 {' d2 L: x( \* K- E/ r  {9 G- {/ L: a
g = m+1; // Z[m+1:r]的游标
5 n0 m/ P2 @+ G1 W1 j5 p4 ^! r
. s  @6 h2 v7 v5 p" J7 R5 s# Pfor (int i = l; i &lt;= r; i++)
! k: V( J+ @2 S# I1 X; K
- c- K4 y' n* u2 n; sif (Y.p &gt; m) Z[g++] = Y;
' G  Y+ Q- Y/ [
* u- h3 ], p! e) L& ?0 v1 nelse Z[f++] = Y;
+ S# [0 ^" [+ e9 X3 [( Y+ R! U
7 b2 v% e0 R+ X9 v6 v% o, N# z" E// 对以上两个部分进行求解
; D% u: S5 d( z2 ~3 Y* ~- S2 t' W, t8 R
c l o s e ( X , Z , Y, l , m , a , b , d ) ;
+ I0 G3 P; K& M/ m9 h1 x! Y! m8 y' b: D7 f/ ]; ]8 S' P
float dr;  ]# [" @& K2 r
1 M9 t+ X% L; a. o6 ~: Y
Point1 ar, br;2 v% Z0 O5 D0 D0 L

2 u2 ^8 X; S" q( Y" |0 \c l o s e ( X , Z , Y, m + 1 , r, a r, b r, d r ) ;
) `6 f9 _5 g9 X9 ^& P2 e
4 q" {3 l2 T3 @5 p) _% J9 g// (a,b) 是两者中较近的点对
; H2 [8 b) h/ }7 |& @
" g" K5 P* U* I3 xif (dr &lt; d) {a = ar;( v. e6 x5 ~5 x, T6 V/ {/ M

. i& v9 ]9 `( Y' C$ q$ bb = br;/ r/ L. U# O, q# ?( W0 A; x8 s

, h# G/ ]0 g0 I7 z5 Td = dr;}4 v$ H) F5 U1 d3 Y, ?1 \

; ?9 b5 N& w8 xM e r g e ( Z , Y,l,m,r);// 重构Y
" ~* O% }  }9 i4 f' i
& {- s' i+ ]+ Q& q8 ~/ /距离小于d的点放入Z, r3 _5 t5 m* d/ o1 P' a( I: l
0 m( H2 \, t2 @9 y! W* x: J
int k = l; // Z的游标
6 ?, Q1 s- w6 c/ C6 K6 `$ H
# w# c2 U6 K2 l1 q  n6 wfor (i = l; i &lt;= r; i++)
0 F& q, E( J5 |' e/ b; B5 n& F) H
# p: u( a' l' ?2 qif (fabs(Y[m].x - Y.x) &lt; d) Z[k++] = Y;
1 R  i3 q' D6 Z8 m3 G, F
& L3 f9 u3 E/ g5 Z// 通过检查Z [ l : k - 1 ]中的所有点对,寻找较近的点对
5 s" P4 @5 x! i" T/ ~+ v5 B0 G2 x4 j+ E
- J- O+ a0 A* W4 Z% m& V- ]% |for (i = l; i &lt; k; i++){
" i5 o' F4 g* K0 k1 x# ]3 S% r7 V! a. ~- e# r. Q
for (int j = i+1; j &lt; k &amp;&amp; Z[j].y - Z.y &lt; d;
+ V9 \: `9 T; H& r2 [( i" }, n$ Q4 ~% ^9 }% C  ]
j + + ) {
5 i% V! P; ^9 l! V# p0 v; l0 a. [+ [4 S* L% B
float dp = dist(Z, Z[j]);8 [9 i) D6 M' }. b. ^/ j

8 T! X" A1 f" d+ Z+ j8 F# {- Bif (dp &lt; d) {// 较近的点对
' P2 x% a: U3 u+ `
* Z; g. X- ]4 Kd = dp;
" _  y4 z  v1 O/ z* I/ r/ o- x& P' ?' c" ~
a = X[Z.p];
$ f  \4 N4 [* ]/ c; ]! i1 X1 U. Y( t. t3 {& E+ R
b = X[Z[j].p];}
7 u; l, k0 L; {; l3 S
+ x0 @* k8 ]: ]9 x3 T0 Z}5 Y! a  F( S  Z* j1 Y

3 }2 t* }3 ?( @}
, `! X  I; f1 y( }% V( ~& t2 o+ S) s; y( Z% Z
}
0 W; L7 ]$ u% ~$ R* M9 W
, O. J3 l7 {* }- E4 |函数c l o s e(见程序1 4 - 11)用来确定X[1:r] 中的最近点对。假定这些点按x 坐标排序。在Y [ 1 : r ]中对这些点按y 坐标排序。Z[ 1 : r ]用来存放中间结果。找到最近点对以后,将在a, b中返回最近点对,在d 中返回距离,数组Y被恢复为输入状态。函数并未修改数组X。  B. Q  V# q+ ]. v- G3 Z  ?

- K* I6 a& r3 E' W! b" x+ F. M首先考察“小问题”,即少于四个点的点集。因为分割过程不会产生少于两点的数组,因此只需要处理两点和三点的情形。对于这两种情形,可以尝试所有的可能性。当点数超过三个时,通过计算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 ]。
) l) L6 g  N. v7 Q1 W' ~2 Y
: O  m) h# _: K) G5 P9 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
2 p2 n) e4 z" R# b- J& h$ d& E, j5 u' a# s' s, V
还是在RB中)与Z[j] 配对来实现,其中i<j 且Z [ j ] . y - Z [ i ] . y< 。对每一个Z [ i ],在2 × 区域内所检查的点如图1 4 - 1 7所示。由于在每个2 × 子区域内的点至少相距。因此每一个子区域中的点数不会超过四个,所以与Z [ i ]配对的点Z [ j ]最多有七个。
, T6 [. e" [. ?7 O) x3 ~) E; }/ Z  M) y+ c4 y2 H$ M5 i
2. 复杂性分析
7 |! M. `# w: n1 w$ l9 t+ |9 [% x0 k7 d+ g1 N7 N1 M% {8 U
令t (n) 代表处理n 个点时,函数close 所需要的时间。当n<4时,t (n) 等于某个常数d。当n≥4时,需花费(n) 时间来完成以下工作:将点集划分为两个部分,两次递归调用后重构Y,淘汰距分割线很远的点,寻找更好的第三类点对。两次递归调用需分别耗时t (「n /2ù」和t (?n /2?).5 d" t" @/ v1 |' i1 W0 d

" r8 j) K. M" z" i7 T这个递归式与归并排序的递归式完全一样,其结果为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-20 10:03 , Processed in 0.807319 second(s), 52 queries .

回顶部