棋盤覆蓋分析與實現
一.什么是棋盤覆蓋?
首先來了解什么是特殊方格,在一個2^k*2^k個方格組成的棋盤中,若恰有一個方格與其他方格不同,則稱該方格為特殊方格,顯然,特殊方格出現的位置有4^k種情況,即k>=0,有4^k種不同的特殊棋盤
棋盤覆蓋:用4種不同的L型骨牌覆蓋一個給定的特殊棋盤(即特殊方格的位置已經確定了)上除去特殊方格外的所有方格,且任何兩個L型骨牌不得重復覆蓋,按照規則,我們很容易知道,在2^k*2^k的棋盤覆蓋中,用到的L型骨盤數恰為(4^k-1)/3,即(所有方格個數-特殊方格個數)/3
如下圖,為k=2時的一個特殊棋盤(相同顏色的三個小方格組成一個L型骨牌)和4種不同形態的L型骨牌,藍色的為特殊方格
k=2時的一個特殊棋盤 4種不用類型的L型骨牌
二.實現棋盤覆蓋的思路和方法
棋盤覆蓋實現的基本方法為分治法,是設計棋盤覆蓋的一個簡介的問題,那什么是分治法?
分治法的基本思路:將一個規模為n的問題分解為k個規模較小的子問題,這些子問題相互獨立且與原問題相同。遞歸地解決這些子問題,然后將各個子問題的解合並得到原問題的解。簡單地說,就是將規模為n的問題自頂向下分解,直到小問題分解到足夠小,可以解決時,再自底向上合並,從而得到原來的解。nxi
分析思路:當k〉0時,將2^k*2^k棋盤分割為4個2^k-1*2^k-1子棋盤,如圖
特殊方格必定位於這四個小棋盤中,其余三個子棋盤沒有特殊方格,為了將這三個無特殊方格的子棋盤轉換為特殊棋盤,我們可以用一個L型骨盤覆蓋這三個較小棋盤的會合處,如圖所示
從圖上可以看出,這三個子棋盤上被L型骨牌覆蓋的方格就成為該棋盤上的特殊方格,從而將問題分解為4個較小規模的棋盤覆蓋問題。遞歸地使用這種分割方法,直至棋盤簡化為1*1棋盤,就結束遞歸。
實現這種算法的分析:每次都對分割后的四個小方塊進行判斷,判斷特殊方格是否在里面。這里的判斷的方法是每次先記錄下整個大方塊的左上角方格的行列坐標,然后再與特殊方格坐標進行比較,就可以知道特殊方格是否在該塊中。如果特殊方塊在里面,這直接遞歸下去求即可,如果不在,這根據分割的四個方塊的不同位置,把右下角、左下角、右上角或者左上角的方格標記為特殊方塊,然后繼續遞歸。在遞歸函數里,還要有一個變量s來記錄邊的方格數,每次對方塊進行划分時,邊的方格數都會減半,這個變量是為了方便判斷特殊方格的位置。
三.棋盤覆蓋的具體實現代碼
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int num = 0; 5 int Matrix[100][100]; 6 void chessBoard(int tr, int tc, int dr, int dc, int size); 7 int main() 8 { 9 int size,r,c,row,col; 10 printf("請輸入棋盤的行列號"); 11 scanf("%d",&size); 12 printf("請輸入特殊方格的行列號"); 13 scanf("%d %d",&row,&col); 14 chessBoard(0,0,row,col,size); 15 16 for (r = 0; r < size; r++) 17 { 18 for (c = 0; c < size; c++) 19 { 20 printf("%2d ",Matrix[r][c]); 21 } 22 printf("\n"); 23 } 24 25 return 0; 26 } 27 28 void chessBoard(int tr, int tc, int dr, int dc, int size) 29 { 30 31 int s,t; 32 if (size==1) return; 33 s = size/2; //分割棋盤 34 t = ++num; //L型骨牌號 35 if (dr < tr + s && dc < tc +s) //覆蓋左上角子棋盤 36 { 37 //特殊方格在此棋盤中 38 chessBoard(tr,tc,dr,dc,s); 39 } 40 else //此棋盤中無特殊方格 41 { 42 //用t號L型骨牌覆蓋右下角 43 Matrix[tr+s-1][tc+s-1] = t; 44 //覆蓋其余方格 45 chessBoard(tr,tc,tr+s-1,tc+s-1,s); 46 } 47 //覆蓋右上角子棋盤 48 if (dr < tr + s && dc >= tc + s ) // 49 { 50 //特殊方格在此棋盤中 51 chessBoard(tr,tc+s,dr,dc,s); 52 } 53 else //此棋盤中無特殊方格 54 { 55 //用t號L型骨牌覆蓋左下角 56 Matrix[tr+s-1][tc+s] = t; 57 //覆蓋其余方格 58 chessBoard(tr,tc+s,tr+s-1,tc+s,s); 59 } 60 //覆蓋左下角子棋盤 61 if (dr >= tr + s && dc < tc + s) 62 { 63 //特殊方格在此棋盤中 64 chessBoard(tr+s,tc,dr,dc,s); 65 } 66 else 67 { 68 //用t號L型骨牌覆蓋右上角 69 Matrix[tr+s][tc+s-1] = t; 70 //覆蓋其余方格 71 chessBoard(tr+s,tc,tr+s,tc+s-1,s); 72 } 73 //覆蓋右下角子棋盤 74 if (dr >= tr + s && dc >= tc + s) 75 { 76 //特殊方格在此棋盤中 77 chessBoard(tr+s,tc+s,dr,dc,s); 78 } 79 else 80 { 81 //用t號L型骨牌覆蓋左上角 82 Matrix[tr+s][tc+s] = t; 83 //覆蓋其余方格 84 chessBoard(tr+s,tc+s,tr+s,tc+s,s); 85 } 86 87 }
運行結果如下圖