<b>残缺棋盘</b> # ?6 n3 f1 n; Y<>残缺棋盘(defective chessboard)是一个有2k×2k 个方格的棋盘,其中恰有一个方格残缺。图2 - 3给出k≤2时各种可能的残缺棋盘,其中残缺的方格用阴影表示。注意当k= 0时,仅存在一种可能的残缺棋盘(如图1 4 - 3 a所示)。事实上,对于任意k,恰好存在22k 种不同的残缺棋盘。 9 N1 e. H! M# B; N ) P4 V& N& ~9 m" D9 W残缺棋盘的问题要求用三格板(t r i o m i n o e s)覆盖残缺棋盘(如图1 4 - 4所示)。在此覆盖中,两个三格板不能重叠,三格板不能覆盖残缺方格,但必须覆盖其他所有的方格。在这种限制条件下,所需要的三格板总数为( 22k -1 ) / 3。可以验证( 22k -1 ) / 3是一个整数。k 为0的残缺棋盘很容易被覆盖,因为它没有非残缺的方格,用于覆盖的三格板的数目为0。当k= 1时,正好存在3个非残缺的方格,并且这三个方格可用图1 4 - 4中的某一方向的三格板来覆盖。 5 R$ u2 P; X; j# `8 m) ` . c5 `# R5 t/ P8 M用分而治之方法可以很好地解决残缺棋盘问题。这一方法可将覆盖2k×2k 残缺棋盘的问题转化为覆盖较小残缺棋盘的问题。2k×2k 棋盘一个很自然的划分方法就是将它划分为如图1 4 - 5 a所示的4个2k - 1×2k - 1 棋盘。注意到当完成这种划分后, 4个小棋盘中仅仅有一个棋盘存在残缺方格(因为原来的2k×2k 棋盘仅仅有一个残缺方格)。首先覆盖其中包含残缺方格的2k - 1×2k - 1 残缺棋盘,然后把剩下的3个小棋盘转变为残缺棋盘,为此将一个三格板放在由这3个小棋盘形成的角上,如图14-5b 所示,其中原2k×2k 棋盘中的残缺方格落入左上角的2k - 1×2k - 1 棋盘。可以采用这种分割技术递归地覆盖2k×2k 残缺棋盘。当棋盘的大小减为1×1时,递归过程终止。此时1×1的棋盘中仅仅包含一个方格且此方格残缺,所以无需放置三格板。 $ ^& M5 ^5 c Q3 i5 g/ t K7 w4 G$ C8 [
可以将上述分而治之算法编写成一个递归的C++ 函数Ti l e B o a r d (见程序1 4 - 2 )。该函数定义了一个全局的二维整数数组变量B o a r d来表示棋盘。B o a r d [ 0 ] [ 0 ]表示棋盘中左上角的方格。该函数还定义了一个全局整数变量t i l e,其初始值为0。函数的输入参数如下: 1 T4 F+ j* j$ i' `% Y! x- X8 y( d$ R' f9 u
? tr 棋盘中左上角方格所在行。 7 ~+ p; `1 t9 v" |4 o, f( v: s( r b n5 X; c
? tc 棋盘中左上角方格所在列。( Z! w8 j3 |1 p) e9 f
+ J, [4 d W% y! F' y? dr 残缺方块所在行。 3 g* W: w% N8 A) F+ p" \ z3 g6 o/ X5 Q) a4 g6 u* v5 ~
? dl 残缺方块所在列。 2 Y0 p0 p5 s. v( p+ b; F- e; h 1 t& Z' i ]9 E2 _& p3 h? size 棋盘的行数或列数。 & L/ M/ Y1 i2 B5 h/ ^. y; Q. @2 v' v
Ti l e B o a r d函数的调用格式为Ti l e B o a r d(0,0, dr, dc,size),其中s i z e = 2k。覆盖残缺棋盘所需要的三格板数目为( s i z e2 -1 ) / 3。函数TileBoard 用整数1到( s i z e2-1 ) / 3来表示这些三格板,并用三格板的标号来标记被该三格板覆盖的非残缺方格。 / C7 @/ ^$ {5 B3 {3 \ R * z$ f4 W# l! b Q- |令t (k) 为函数Ti l e B o a r d覆盖一个2k×2k 残缺棋盘所需要的时间。当k= 0时,s i z e等于1,覆盖它将花费常数时间d。当k > 0时,将进行4次递归的函数调用,这些调用需花费的时间为4t (k-1 )。除了这些时间外, if 条件测试和覆盖3个非残缺方格也需要时间,假设用常数c 表示这些额外时间。可以得到以下递归表达式:4 C0 e! q; ~8 e& M6 z e/ q
8 j B+ t- r5 a6 `- \' s程序14-2 覆盖残缺棋盘 & ]' Q: I6 r6 W0 k8 r0 z 4 |9 |2 ^/ R2 L& r% O* k, Mvoid TileBoard(int tr, int tc, int dr, int dc, int size)9 _/ m4 l& G. ?. t; v8 G0 m4 b
" O( @9 B0 I T' E0 Q5 D
{// 覆盖残缺棋盘+ n& X; C$ Q$ {
2 O% J+ S. p8 L$ N: Iif (size == 1) return; T( C* V5 U1 W3 `* H) }* Z8 z+ c% Q2 ~! D& T
int t = tile++, // 所使用的三格板的数目8 S) _( \8 ~6 W+ P; ~7 @# B
' k) R' ^0 r4 [0 E- h9 _( a1 ~
s = size/2; // 象限大小 5 `4 m1 A% P- z9 `2 d" {( B9 g4 Z& ] `3 e0 O& T
/ /覆盖左上象限 , O! @0 C2 k4 w, t' X% f, x( S, Y- {) N& E ]5 V7 H+ m: k, |
if (dr < tr + s && dc < tc + s)4 G6 c8 Z/ p% I+ b' R% T: c
" d3 c" E* [1 ]+ F+ J1 ~// 残缺方格位于本象限 1 r6 C- C% z; h" @" ?5 V6 t0 c7 g( c8 d+ ~, Q! e
Ti l e B o a r d ( t r, tc, dr, dc, s); 3 B$ i1 i7 {, J Y% c9 s' D3 x. r9 s$ A9 W% e6 S- i% m+ z8 e
else {// 本象限中没有残缺方格 + N5 g7 y) C/ h) R. e/ K `( o ; F. r z7 }: [( J; C- o! r0 u8 }. l// 把三格板t 放在右下角 , V+ r3 Q9 ]+ z: C5 D9 p" i$ x3 N$ h
Board[tr + s - 1][tc + s - 1] = t; $ ^2 h- n6 g9 @9 F; _ ! g2 }$ v; l6 o4 x8 P' |$ J// 覆盖其余部分 % J4 ~5 R4 q9 T9 W! o+ Y* b0 W, x7 F1 M; D5 `# Z# A
Ti l e B o a r d ( t r, tc, tr+s-1, tc+s-1, s);}1 h3 O/ v x0 Q1 E0 J+ m, Z7 }
# X- m& S3 q, U% O
/ /覆盖右上象限 8 c& G& D; ~) P; ^1 Q% x ) n6 L3 U8 H% d# B0 aif (dr < tr + s && dc >= tc + s)* w/ j- _" N, F& Y# M
/ P1 l1 N2 J6 p2 _' J* H
// 残缺方格位于本象限7 N7 X( {5 N% |* C) }- ^9 q/ d/ H
6 ? z6 U' Y) xTi l e B o a r d ( t r, tc+s, dr, dc, s);! A8 G; U, Z4 d* O3 l2 A
: w p/ _9 H" a8 ~else {// 本象限中没有残缺方格( X" i" H6 c& `/ g0 {3 X
& w9 P2 b1 d8 F `: B" _// 把三格板t 放在左下角 , q* o* T3 U1 o" P# V" d$ X5 J; L, H3 v& G2 ?4 j
Board[tr + s - 1][tc + s] = t; ! @* p9 Y! T" m/ }: l4 f / Q' |2 D" ^5 k$ R3 T: A9 m# }" c// 覆盖其余部分 # e% G7 u* T3 C5 v W3 |) z; U' W$ b
Ti l e B o a r d ( t r, tc+s, tr+s-1, tc+s, s);}0 G5 |8 m8 H, D5 q
& i9 L) A G, n5 R2 ^! Z6 X
/ /覆盖左下象限* c! Q9 n$ J* T( a* I' `6 [
7 O d& d, O! K
if (dr >= tr + s && dc < tc + s) 3 a/ p4 `& u5 h( X+ C" I( y) y, s3 B % x/ z4 B1 _3 c( J. [ V// 残缺方格位于本象限9 i& p2 c$ G' K0 W& I: j
; Y2 @; H+ ]1 C8 d- ^
TileBoard(tr+s, tc, dr, dc, s); 2 B+ W1 u! L: e3 [7 @. J) ]1 Z: w5 I. v0 \
else {// 把三格板t 放在右上角 , T8 W$ T+ B! r4 R + n$ T) f; e, N/ O! i* S2 hBoard[tr + s][tc + s - 1] = t; 3 m% I5 l" o. \# u4 P7 ~ " }" ]# V7 t& p; f& ^// 覆盖其余部分 7 B% K- C/ T# i' G! X 0 B$ w' e$ L; j4 YTileBoard(tr+s, tc, tr+s, tc+s-1, s);}. z& L: M4 Z7 ^' w( p
( H9 d3 T! T. ^8 |0 |* A! m7 W// 覆盖右下象限 4 \3 r7 M8 `% S$ J" P: u6 Y# p; p- u
if (dr >= tr + s && dc >= tc + s) ( i1 |& C: \$ @* x, i5 W2 R- M; B9 R L" u: T
// 残缺方格位于本象限 ( v" N q5 O+ Q3 b% M/ a$ @- d2 q1 d' K0 g
TileBoard(tr+s, tc+s, dr, dc, s);: j, Y4 V- t# u1 G$ q9 u r* q8 b
/ a) j, A7 L6 Y4 S: i' m$ y E
else {// 把三格板t 放在左上角( X5 S& V( ~: u- n
4 U2 S; V+ r: Z. Z4 v) H) TBoard[tr + s][tc + s] = t; ^5 q8 g) F7 P) T( B4 s , Q n( T$ V- {5 }. ?7 ]// 覆盖其余部分 E% m' E" f6 V* ]$ `; s3 A0 ^0 U' [
, F# P" d. u/ H9 A' s+ }: k1 f
TileBoard(tr+s, tc+s, tr+s, tc+s, s);} ' E* V2 S9 {8 F* T( l! V) c1 [$ P% [8 p$ b
}: o' e. f' h1 _" ?9 a