QQ登录

只需要一步,快速开始

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

距离最近的点对

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-4 05:18 |只看该作者 |正序浏览
|招呼Ta 关注Ta
<>给定n 个点(xi,yi)(1≤i≤n),要求找出其中距离最近的两个点。% S2 t! @3 C" t% p3 z5 c

  D7 w9 }* z) a例14-7 假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。若知道任意两个洞的最小距离,可估计金属断裂的概率。这种最小距离问题实际上也就是距离最近的点对问题。, k8 K' z; Y. |

7 }" R, V- T. V& F* N) P通过检查所有的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进行递归求解。) k  L% Y0 w) w3 T7 m: Z0 C
0 _" v* D1 g# m9 E
4 S+ I( Q% W- X6 w6 x8 Q; y
if (n较小) {用直接法寻找最近点对
) q" {; x9 z- B7 b( R
( v0 Z' N' s9 }0 }3 dR e t u r n ; }) P+ l4 Q3 N5 E! e$ M5 j. T
; C4 l' r- @8 x& n
// n较大
( t& p$ a. E0 o8 T* ]) x* R
- d5 b, L* s# T; J将点集分成大致相等的两个部分A和B3 b( u3 @' B( i. w2 W9 C/ I

: q. x, [: C  q3 z* P" ^确定A和B中的最近点对2 _$ A# T: G' ?. A* v; \  }

/ p2 o! F' [2 z' X% j. O! r& Q确定一点在A中、另一点在B中的最近点对9 H4 V/ I; C# M5 T6 w
3 k, I# [# A' L4 ]( M( n% ^* [
从上面得到的三对点中,找出距离最小的一对点8 ^, g& q% w, ?. ?6 X

& n" C. ]. g& ^  _图14-13 寻找最近的点对
4 w" Q  d# Q7 e. D- C7 s' V$ ^' j2 ^! s/ a, D
0 s+ S" S- l- ]
为了确定第三种情况下的最近点对,需要采用一种不同的方法。这种方法取决于点集是如何被划分成A、B的。一个合理的划分方法是从xi(中间值)处划一条垂线,线左边的点属于A,线右边的点属于B。位于垂线上的点可在A和B之间分配,以便满足A、B的大小。/ ^  \" U/ I! w, p( `8 t* u/ |
+ C# l" {. M, \5 D. B" x+ B/ w1 p
例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。
% I% g- {$ u# D* Z+ r; K6 ~! d3 |- F8 i" @0 a! K* t. s, g* I/ x( 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)。3 ?* ~" b+ G, e

5 ^- T, ~- R. T$ B+ ?& P例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) 是最近的点对。6 E# s- x& K' A) w
1 [% E- s- L; }& `) G
为了确定一个距离更小的第三类点,RA 中的每个点最多只需和RB 中的6个点比较,如图1 4 - 1 6所示。  ]) q$ T- s  J

) `1 u* O( i6 j$ X3 r1. 选择数据结构5 ~7 u: [! b! d( s

- l7 L- g2 B) O# ?7 a( I, I9 `为了实现图1 4 - 1 3的分而治之算法,需要确定什么是“小问题”以及如何表示点。由于集合中少于两点时不存在最近点对,因此必须保证分解过程不会产生少于两点的点集。如果将少于四点的点集做为“小问题”,就可以避免产生少于两点的点集。( Z. z" r+ U# H$ g) [
6 c- I& f6 Z1 R
每个点可有三个参数:标号, x 坐标,y 坐标。假设标号为整数,每个点可用P o i n t l类(见程序1 4 - 8)来表示。为了便于按x 坐标对各个点排序,可重载操作符<=。归并排序程序如1 4 -3所示。
- s0 |: o. R6 X  t. w$ a/ P) ?9 `8 [/ B* H# K& [! P' h
程序14-8 点类
  @: i6 j5 ]) O+ [$ L7 |
- q, b2 Q" f. L* Z0 P1 Qclass Point1 {, ^8 i1 K' A% g
; T9 D- c- |8 M/ H: R
friend float dist(const Point1&amp;, const Point1&amp;);+ A+ ]/ _8 d4 K* V; ~0 a- @

  K$ v! @  l) w  [, V9 [friend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);
4 a- ~) D3 k  W$ E6 E' T6 P* @1 d, K. }( L
friend bool closest(Point1 *, int, Point1&amp;, Point1&amp;,float&amp;);
9 |( o9 T3 {6 n* Z* E- ~2 z  f+ z* S) Y. @
friend void main();4 c# h, P8 |9 N3 F/ T( A; g3 p
# G6 c8 S  F1 R+ M1 ~8 A2 r
p u b l i c :
9 i9 i8 U  g0 n' s, m$ Q
. ?0 T9 o5 p2 k+ E1 Q' e% rint operator&lt;=(Point1 a) const
0 V( j4 K1 c9 V* U6 R
. C6 c: A. B  _8 i2 Y# L. k{return (x &lt;= a.x);}  I3 K* i7 \5 A6 Z+ P! \. |
& o1 h+ [9 Z( y8 {
p r i v a t e :$ E' k' ^/ U+ b- N1 {2 t. W& G- U

" \! l0 B' F) S3 s! b& k' hint ID; // 点的编号
& [0 a; ^8 U2 e
( R- Q/ Z5 I% \" yfloat x, y; // 点坐标0 G# K! x/ ]& ]. K

  h4 n. u5 }: K} ;
% m) f' d  j% Z$ ^' b6 L4 ]. `( I7 t$ W! {' P* s" U; k5 n
class Point2 {
1 C  R  w; ^6 `$ i( X
3 V- o8 t: H4 F5 ]8 kfriend float dist(const Point2&amp;, const Point2&amp;);* U$ O: d' j  y0 c" L
4 g: r$ @7 ]; ?7 m' m" |5 t
friend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);
/ `, X' f! C2 T) l  i, c) q: z, q$ L$ c; R" S4 L3 X" x
friend bool closest(Point1 *, int, Point1&amp;, Point1&amp;, float&amp;);
. Z2 O+ T! {) o1 M6 y) R* E
- d2 G: V+ y; H9 c3 Y" Q+ g" `, rfriend void main();9 Y& S2 y& ~! Y) H; |5 p* N

9 g7 k# Z% C4 k* F3 l4 dp u b l i c :
" N* b# i6 I% ~' `( ?7 {. E0 a4 a8 i. X0 |  F% v6 e: D
int operator&lt;=(Point2 a) const
. }0 O! m# d' J0 `" |2 {4 Z$ k- r" I6 n
{return (y &lt;= a.y);}
* ?* L6 Q4 r, L! |4 I1 R
3 s* k9 V# \5 Wp r i v a t e :
: X2 R( n7 Q0 m5 C: L8 O, [# ^
int p; // 数组X中相同点的索引- C) c& P5 f  z' r1 E" I
/ w5 l& n+ x" D! F' u
float x, y; // 点坐标
3 X9 m% E* [: h( m- [) ~/ d; m; X7 x0 l; e/ {5 @- Y3 L5 C& ^
} ;
9 A$ ~) C# N  k* B4 b* ^
+ [2 t/ R& v# q# Y) _- I9 L2 s所输入的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中的对应点。- b5 c9 p9 y( ?/ F3 b% z3 g
0 R/ n' s% l0 X, Z6 G
确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数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类的友元。
. q" J% g7 B! o4 m8 n& \/ S
( R& e4 z; {( O; O+ [! [8 R程序14-9 计算两点距离- X' X3 ?5 C9 ^9 b

7 t' M* q2 u) p+ B& Ctemplate<CLASS T>
; y1 r$ P4 e8 Q0 z! q
: h, \) A  ?% ~inline float dist(const T&amp; u, const T&amp; v)0 A" X6 `4 k# `1 v
9 X" _2 r8 G- C  p+ ]
{ / /计算点u 和v之间的距离: v, h- L: N! z' ?# `/ E

7 o3 C* F& M/ P  E/ o$ w; tfloat dx = u.x-v. x ;1 l6 N+ B4 \! N

6 ?% A3 \) q2 |+ Yfloat dy = u.y-v. y ;2 ?9 o- d7 ?% S2 v7 M
& F  ?3 |5 E2 j- F
return sqrt(dx * dx + dy * dy);
6 m7 G1 E  E+ T7 V; y5 P/ X7 t7 [/ _: r3 T3 M
}
2 [9 R5 _' d" g2 z( D# [" s6 x8 M' i/ n( B7 D4 I
如果点的数目少于两个,则函数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 ),该函数实际求解最近点对。
" N/ s$ z7 d  f: U/ C% U3 k3 _. j, p/ \: Z2 [
程序14-10 预处理及调用c l o s e  I$ k2 H2 A4 q- o9 ^

4 n8 L3 b/ Q. Rbool closest(Point1 X[], int n, Point1&amp; a, Point1&amp; b, float&amp; d)+ ~' T4 k+ D# e9 l
0 ]# b* u5 I& E$ w
{// 在n &gt;= 2 个点中寻找最近点对
& g) |# Y( w+ r; R
* [1 d. O: o5 ~& K1 H0 o" g! }// 如果少于2个点,则返回f a l s e& Y( A5 F* [" ~* @9 u1 F

/ f; }) K3 P- U: s/ H// 否则,在a 和b中返回距离最近的两个点
0 i6 ^8 n! u4 x: o5 S! |% u
2 N+ l; |4 s7 |% a2 {/ nif (n &lt; 2) return false;- w# E2 k1 i9 l) E1 M2 P
5 K( M( z$ {. X* Y1 b- n
// 按x坐标排序' o0 E6 u- h7 E- n# w, j

* l0 U+ Q7 F2 W4 @; X. qM e r g e S o r t ( X , n ) ;
* P8 S: e0 N3 ?( x( s) E) _" }( e" _$ L5 X2 N. @
// 创建一个按y坐标排序的点数组. W% b& F, w  L3 n- c) ^) h
5 W  [8 p6 \9 d# A# d$ e" W
Point2 *Y = new Point2 [n];
( \: O3 R: n$ L% E
% F7 u" c8 k6 d0 N/ B; xfor (int i = 0; i &lt; n; i++) {# \1 O# k' k4 z; W, C: U/ N+ r" Z

1 ?$ R0 s$ u( B9 A" H+ [- Y1 |  x// 将点i 从X 复制到Y
% X1 U+ K) q# `6 n3 {4 Q
  h! L5 s4 v& @: XY.p = i;
# A+ I2 ~& q/ O3 Y9 K0 a; A
4 s9 {  m7 R' r5 }3 K% p  KY.x = X.x;0 ?( n) W$ b$ s1 o, @
! e& [6 p! @/ J% g& z/ [- ?
Y.y = X.y;
" \4 y# @5 |/ p/ r' r4 v" _
' [9 N0 f% V3 M( A4 w3 T}
1 G7 Y: B% j( ]. f+ H! H1 b/ x. I3 f( z2 }8 J
M e r g e S o r t ( Y,n); // 按y坐标排序
. c9 k( a0 z- H$ }: @3 A. D- \* a7 X2 h* t" |
// 创建临时数组  ^: B8 g- h: t3 r. _
+ C+ q: ~+ X5 b4 f; n
Point2 *Z = new Point2 [n];7 q3 k8 Y, m# @% K( p

& @' d# k! k& p/ h( r// 寻找最近点对  _& g9 j, v- k
# t- e+ j' X% Q  u5 m3 G
c l o s e ( X , Y, Z , 0 , n - 1 , a , b , d ) ;
  T/ X: J% p& W( a" Y+ M7 G& A& W8 K1 u* w) S' D. U$ j" n4 y- E8 N
// 删除数组并返回1 C$ q1 g- P* P4 s

: D4 @9 z3 x+ i) d% p5 R/ K1 `6 odelete [] Y;$ z% t% y  c6 h+ x  u3 I
: f- C% D, G% c' A! ]. @7 e: J5 w
delete [] Z;
! [4 @) e& R  @* o. A
: h( m( z( k2 C5 Treturn true;' D8 @. q1 s+ G* {7 p

* P1 c# X$ ^1 S* x& c1 {}
8 v/ z  {' P) z8 L9 ~3 Y. @: A+ U) p& D; h" Y+ {
程序1 4 - 11 计算最近点对
* v  X6 x! M: H3 p/ G' q& y6 a0 Q. N. A& _, e8 |6 K. }6 `. ^
void close(Point1 X[], Point2 Y[], Point2 Z[], int l, int r, Point1&amp; a, Point1&amp; b, float&amp; d)1 b( K' K* E. o+ g

# {2 @) `3 p, t# ~{//X[l:r] 按x坐标排序
. V8 ]0 j2 \. S  t! y% j' e0 i; `1 B2 c$ Y
//Y[l:r] 按y坐标排序. ]! g4 ^' ~1 H  p5 A

. {6 O, X; y+ e- ]5 `3 W- Uif (r-l == 1) {// 两个点% W" n2 m! h0 u' O; C

& c/ I# k- W; f' P# Ua = X[l];* H5 b6 N8 v8 S8 R: [+ q8 N% H+ @8 d

. \- b: e+ J/ L/ [4 Y5 q1 ^9 Eb = X[r];$ ?* ?" e$ }! A( Q% B) Q  X* j
' m- E: d; D) a  X; I+ A* h
d = dist(X[l], X[r]);  O9 n' o5 T4 ]1 R5 l
  `' {3 g. g+ z* m) O7 O
r e t u r n ; }
2 r5 b' h: d4 x) g- ~: G- X6 l
: _* _, z9 C: xif (r-l == 2) {// 三个点
8 T* D: p" O  e7 H* o( _$ S1 y& z- L" `; @* b2 c8 U, K) }
// 计算所有点对之间的距离
% V" y: j% A8 r5 s( g4 T/ A1 I, M3 B; U( V* A% Q3 ?$ e
float d1 = dist(X[l], X[l+1]);
8 F: C' b6 e& ]* g  d9 b! r& Y( G' y/ t0 K' T
float d2 = dist(X[l+1], X[r]);
& _8 q* g  ]( m7 T7 B( c8 O) ^0 k* b
float d3 = dist(X[l], X[r]);
& ]* J& j) [7 n! P" R
# F/ `% v6 a5 C# X  z# z// 寻找最近点对: Z! Q5 c' I' [" I1 E) i% N

+ x* V$ u9 i8 b" j) S/ Vif (d1 &lt;= d2 &amp;&amp; d1 &lt;= d3) {
: |( r* o$ X) h9 R
2 J5 Q* d. a, Ra = X[l];& m1 P1 ^) c- B( t1 \8 p

" a% E/ W" X% Y$ A$ U& D6 L% B0 db = X[l+1];
% P* E4 W% A( F7 [- \  g5 f9 Q0 Q5 B  R2 y
d = d1;
" c3 ~4 H4 _1 G
4 i4 Q8 y% J1 U5 f, Fr e t u r n ; }' A4 f" p& R, _+ j

' o0 w* d7 h! mif (d2 &lt;= d3) {a = X[l+1];
: q9 b" ^( m6 w" T0 D8 w9 z. j! s
( z; D9 b# k9 N6 z4 ]& Eb = X[r];
& _+ e/ o% b7 g2 D% P* ^( D' p
9 i- Y2 D7 k* Y$ b4 pd = d2;}0 \2 Z( k( p3 x! d
3 S, F2 P7 a2 u4 o% G
else {a = X[l];/ ~1 U9 B, l3 G" Q

: D5 B' ~: k% `6 t2 V% \) Gb = X[r];
: b7 n- N' F8 d3 k7 N
/ z+ }+ f: v: _2 Id = d3;}
% N' s& M, i; U4 l
2 l# Y8 h" M, ~# m# er e t u r n ; }+ \* x8 f) N) h: T4 E8 D

; z, q$ Q  a  s, D/ /多于三个点,划分为两部分) e& e4 _3 {' d

$ A, b" B& F& R) I* ~' gint m = (l+r)/2; // X[l:m] 在A中,余下的在B中
( v; R" T$ O, i$ G! @! u. ^0 h1 Q1 L4 }* J* u& C) r7 G- F
// 在Z[l:m] 和Z [ m + 1 : r ]中创建按y排序的表" ~8 ]" E& k4 a( S- j
; I! g. _( Y1 b: V# ]% s8 `
int f = l, // Z[l:m]的游标
% _. r: g* |' [6 [# H6 T4 O) }
( z8 g6 [, O; V2 [+ f- ^9 i* z% Mg = m+1; // Z[m+1:r]的游标& N, I" a- K6 J
1 s1 o& f, C  y5 V2 j. d
for (int i = l; i &lt;= r; i++): g! ?6 n- T6 b6 s

1 w7 @3 t$ k+ Z/ D; \5 g. Rif (Y.p &gt; m) Z[g++] = Y;
7 Y" Y. `2 ]! z+ D9 {- x
  \( n6 f1 a: {7 k& J3 t, helse Z[f++] = Y;+ L5 i' q/ E0 s5 e* S. \) y

- V, |9 n5 \6 U4 _3 Z- _0 U' i// 对以上两个部分进行求解
1 o* a$ Z9 u) }* w0 A6 Z3 P9 S, L4 m" d& M4 t
c l o s e ( X , Z , Y, l , m , a , b , d ) ;. f; h# R& W( I; {* ^/ w9 l- V7 V
5 s, V6 v5 G; _8 _" A
float dr;8 v5 C- f7 Y' Y) U
! C- B2 I) x, o7 A6 J% y
Point1 ar, br;/ |6 z  n( G* R# |+ R/ D

* t+ K1 Y. r1 [: sc l o s e ( X , Z , Y, m + 1 , r, a r, b r, d r ) ;! z) R9 F3 ]# }2 a

4 g2 X8 Y* B9 T0 x// (a,b) 是两者中较近的点对, O% ~* X; B/ B# f# U
; R4 _) r. S* X
if (dr &lt; d) {a = ar;
* b4 P# R  |7 p9 M' o! m& e) X. I: B' @! C6 J
b = br;/ {: }5 u) c8 S, O
) s/ W' g! r+ q0 U
d = dr;}5 D' d( G2 ^; Q

4 @, a, {& i# L/ {8 A0 @* uM e r g e ( Z , Y,l,m,r);// 重构Y
, m- R! n( j- w! z+ T8 h; G
6 K  C+ m' _0 j4 s/ /距离小于d的点放入Z: C& F' Z$ ]$ }" Y, ]3 Q
" p2 E, y# g2 h2 p* U
int k = l; // Z的游标1 {& o! U5 k8 a) B# V+ p9 W  Q9 d
4 @7 ~4 O! r8 e
for (i = l; i &lt;= r; i++)
. o6 N  Z- I! E" W. C& R2 I; b! P+ y( D
if (fabs(Y[m].x - Y.x) &lt; d) Z[k++] = Y;
% h( x1 l' D. q2 }, B6 @3 O& ]% R# J4 R
// 通过检查Z [ l : k - 1 ]中的所有点对,寻找较近的点对& d+ A% V9 K  ]- h. L
+ q. X* P. q5 a+ K# f
for (i = l; i &lt; k; i++){/ ?, I1 C. s0 H& d
5 b" S: I) e  b
for (int j = i+1; j &lt; k &amp;&amp; Z[j].y - Z.y &lt; d;
% u9 I% N% {5 x/ H1 ?
& h1 N  I8 g, E2 J% X( L: d: \! ej + + ) {
4 G) Y. n& x& h" u: z2 A0 @2 j5 O6 V# k, }/ Z0 U% r2 Z- X1 U, u  b
float dp = dist(Z, Z[j]);8 d$ r4 ~+ F% \+ @4 B& d
, k4 a" Y- l' u/ A( L
if (dp &lt; d) {// 较近的点对
! U0 \2 q+ [& e% F
+ C. V$ q/ Y: F8 B2 W7 X" V7 pd = dp;3 s& l- ?/ `) I  J
! I3 D3 l: I% w5 }: B
a = X[Z.p];
/ t& a0 h$ g+ z- d" [+ S
+ Z, d) |& e- ?* d) Tb = X[Z[j].p];}( Q1 b3 Z: E$ j* M1 ~; x6 m) ]" D# g

& n) t; r7 I9 R8 t) y9 x}8 w2 E6 m' @% e  B! J

* y. Y2 H+ s6 R  d( k) m: v}
/ F4 Y. ~0 i* |- D3 X5 R" G
8 b* e( f* `9 A" D5 n, w: g6 \+ u3 y/ x}
! d% ?1 S' D8 }1 S8 @( _: t, A5 d) ?9 |
8 ]( G5 U% f. h函数c l o s e(见程序1 4 - 11)用来确定X[1:r] 中的最近点对。假定这些点按x 坐标排序。在Y [ 1 : r ]中对这些点按y 坐标排序。Z[ 1 : r ]用来存放中间结果。找到最近点对以后,将在a, b中返回最近点对,在d 中返回距离,数组Y被恢复为输入状态。函数并未修改数组X。
) Y! N1 o( z2 D9 @8 V
6 {' y$ c# i. O首先考察“小问题”,即少于四个点的点集。因为分割过程不会产生少于两点的数组,因此只需要处理两点和三点的情形。对于这两种情形,可以尝试所有的可能性。当点数超过三个时,通过计算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 ]。+ |$ A% v6 f7 n
' l: y8 {6 |. e$ ?- d7 R
为实现图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
0 n% m4 ^' x0 t: F) O4 l( u; h
8 s" [( T* I# Y# M/ r还是在RB中)与Z[j] 配对来实现,其中i<j 且Z [ j ] . y - Z [ i ] . y< 。对每一个Z [ i ],在2 × 区域内所检查的点如图1 4 - 1 7所示。由于在每个2 × 子区域内的点至少相距。因此每一个子区域中的点数不会超过四个,所以与Z [ i ]配对的点Z [ j ]最多有七个。" h7 f& x0 T. e6 H/ I% A

" N" h- k# _: c( u( F& Q' m# v2. 复杂性分析- R) b; R2 }6 P3 d2 a# b

, ~7 m2 B: y. L) K! y2 B令t (n) 代表处理n 个点时,函数close 所需要的时间。当n<4时,t (n) 等于某个常数d。当n≥4时,需花费(n) 时间来完成以下工作:将点集划分为两个部分,两次递归调用后重构Y,淘汰距分割线很远的点,寻找更好的第三类点对。两次递归调用需分别耗时t (「n /2ù」和t (?n /2?).; ]. s5 X* z- _6 p+ Z: Y

( c& O2 Y5 t, v+ X; V- K; E这个递归式与归并排序的递归式完全一样,其结果为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 18:40 , Processed in 0.435131 second(s), 52 queries .

回顶部