棋盤覆蓋問題
問題描述:
在一個2^k×2^k個方格組成的棋盤中,若有一個方格與其他方格不同,則稱該方格為一特殊方格,且稱該棋盤為一個特殊棋盤.顯然特殊方格在棋盤上出現的位置有4^k種情形.因而對任何k≥0,有4^k種不同的特殊棋盤.
下圖–圖(1)中的特殊棋盤是當k=3時16個特殊棋盤中的一個:
圖(1)
題目要求在棋盤覆蓋問題中,要用下圖-圖(2)所示的4種不同形態的L型骨牌覆蓋一個給定的特殊棋盤上除特殊方格以外的所有方格,且任何2個L型骨牌不得重疊覆蓋.
圖(2)
題目輸入k,輸出棋盤覆蓋的順序。覆蓋策略可以自己選擇。
分析:
這個題其實可以有不同的覆蓋順序。比如:(下圖中的數字表示依次覆蓋的順序)
策略a 策略b 策略c
策略a:
不停地分割尋找殘缺塊所在區域,然后在殘缺塊周圍填充第一塊(這個時候size=2);然后回溯一層,填充偽殘缺塊(這個時候size=4);然后對當前size=4的另外三個子棋盤依次填充(含殘缺塊的子棋盤當然不再填充了。)。
填充完size==4的棋盤后,回溯到size=8的棋盤(假如存在size=8的棋盤的話呵呵),重復剛才的過程:先填充size=8這個棋盤的偽殘缺塊,然后填充另外的三個子棋盤。……
關鍵代碼如下:
完整代碼:
1 #include<stdio.h> 2 int count=0,bord[100][100]; 3 //覆蓋以(tr,tc)為左上角坐標,寬為size的棋盤。殘缺塊或偽殘缺塊坐標為(dr,dc) 4 int cover(int tr,int tc,int size,int dr,int dc); 5 int main() 6 { 7 int x,y,k,size=1; 8 int i,j; 9 scanf("%d%d%d",&k,&x,&y); 10 for(i=1;i<=k;i++) size=size*2;//計算2^k 11 cover(0,0,size,x,y);//對原始棋盤進行覆蓋 12 for(i=0;i<size;i++)//輸出棋盤的覆蓋結果 13 { 14 for(j=0;j<size;j++) 15 { 16 printf("%-2d ",bord[i][j]); 17 } 18 printf("\n"); 19 } 20 return 0; 21 } 22 23 int cover(int tr,int tc,int size,int dr,int dc) 24 { 25 if(size<2) return 0;//假如棋盤分割到不足2*2則直接返回(這時候沒辦法用模板去覆蓋棋盤了) 26 int s; 27 s=size/2;//表示即將被再次分割后的棋盤大小 28 if(dr<(tr+s)&&dc<(tc+s))//表示對當前輸入的棋盤而言,殘缺塊在左上角部分的子棋盤 29 { 30 cover(tr,tc,s,dr,dc);//對左上角子棋盤分割 31 count++; 32 bord[tr+s-1][tc+s]=count;//下面三個賦值語句是用①號模板覆蓋 33 bord[tr+s][tc+s-1]=count; 34 bord[tr+s][tc+s]=count; 35 cover(tr,tc+s,s,tr+s-1,tc+s);//對右上角子棋盤分割 36 cover(tr+s,tc,s,tr+s,tc+s-1);//對左下角子棋盤分割 37 cover(tr+s,tc+s,s,tr+s,tc+s);//對右下角子棋盤分割 38 } 39 else if(dr<(tr+s)&&dc>=(tc+s))//表示對當前輸入的棋盤而言,殘缺塊在右上角部分的子棋盤 40 { 41 cover(tr,tc+s,s,dr,dc);//對右上角子棋盤分割 42 count++; 43 bord[tr+s-1][tc+s-1]=count;//下面三個賦值語句是用②號模板覆蓋 44 bord[tr+s][tc+s-1]=count; 45 bord[tr+s][tc+s]=count; 46 cover(tr,tc,s,tr+s-1,tc+s-1);//對左上角子棋盤分割 47 cover(tr+s,tc,s,tr+s,tc+s-1);//對左下角子棋盤分割 48 cover(tr+s,tc+s,s,tr+s,tc+s);//對右下角子棋盤分割 49 } 50 else if(dr>=(tr+s)&&dc<(tc+s))//表示對當前輸入的棋盤而言,殘缺塊在左下角部分的子棋盤 51 { 52 cover(tr+s,tc,s,dr,dc); 53 count++; 54 bord[tr+s-1][tc+s-1]=count;//下面三個賦值語句是用③號模板覆蓋 55 bord[tr+s-1][tc+s]=count; 56 bord[tr+s][tc+s]=count; 57 cover(tr,tc,s,tr+s-1,tc+s-1); 58 cover(tr,tc+s,s,tr+s-1,tc+s); 59 cover(tr+s,tc+s,s,tr+s,tc+s); 60 } 61 else if(dr>=(tr+s)&&dc>=(tc+s))//表示對當前輸入的棋盤而言,殘缺塊在右下角部分的子棋盤 62 { 63 cover(tr+s,tc+s,s,dr,dc); 64 count++; 65 bord[tr+s-1][tc+s-1]=count;//下面三個賦值語句是用④號模板覆蓋 66 bord[tr+s-1][tc+s]=count; 67 bord[tr+s][tc+s-1]=count; 68 cover(tr,tc,s,tr+s-1,tc+s-1); 69 cover(tr,tc+s,s,tr+s-1,tc+s); 70 cover(tr+s,tc,s,tr+s,tc+s-1); 71 } 72 }
策略b:
每一次分割時,在遞歸進入下一層之前,先填充偽殘缺塊。(因為這個時候已經根據殘缺塊坐標推出可以使用哪種模板填充了。)(這個時候size=n/2)
然后依次處理當前層的四個子棋盤:分割——填充偽殘缺塊——處理更小的子棋盤。
整個程序重復該過程,最終完成填充任務。
關鍵代碼如下:
完整代碼:
1 #include<stdio.h> 2 int count=0,bord[100][100]; 3 //覆蓋以(tr,tc)為左上角坐標,寬為size的棋盤。殘缺塊或偽殘缺塊坐標為(dr,dc) 4 int cover(int tr,int tc,int size,int dr,int dc); 5 int main() 6 { 7 int x,y,k,size=1; 8 int i,j; 9 scanf("%d%d%d",&k,&x,&y); 10 for(i=1;i<=k;i++) size=size*2;//計算2^k 11 cover(0,0,size,x,y);//對原始棋盤進行覆蓋 12 for(i=0;i<size;i++)//輸出棋盤的覆蓋結果 13 { 14 for(j=0;j<size;j++) 15 { 16 printf("%-2d ",bord[i][j]); 17 } 18 printf("\n"); 19 } 20 return 0; 21 } 22 23 int cover(int tr,int tc,int size,int dr,int dc) 24 { 25 if(size<2) return 0;//假如棋盤分割到不足2*2則直接返回(這時候沒辦法用模板去覆蓋棋盤了) 26 int s; 27 s=size/2;//表示即將被再次分割后的棋盤大小 28 if(dr<(tr+s)&&dc<(tc+s))//表示對當前輸入的棋盤而言,殘缺塊在左上角部分的子棋盤 29 { 30 count++; 31 bord[tr+s-1][tc+s]=count;//下面三個賦值語句是用①號模板覆蓋 32 bord[tr+s][tc+s-1]=count; 33 bord[tr+s][tc+s]=count; 34 cover(tr,tc,s,dr,dc);//對左上角子棋盤分割 35 36 cover(tr,tc+s,s,tr+s-1,tc+s);//對右上角子棋盤分割 37 cover(tr+s,tc,s,tr+s,tc+s-1);//對左下角子棋盤分割 38 cover(tr+s,tc+s,s,tr+s,tc+s);//對右下角子棋盤分割 39 } 40 else if(dr<(tr+s)&&dc>=(tc+s))//表示對當前輸入的棋盤而言,殘缺塊在右上角部分的子棋盤 41 { 42 count++; 43 bord[tr+s-1][tc+s-1]=count;//下面三個賦值語句是用②號模板覆蓋 44 bord[tr+s][tc+s-1]=count; 45 bord[tr+s][tc+s]=count; 46 cover(tr,tc+s,s,dr,dc);//對右上角子棋盤分割 47 48 cover(tr,tc,s,tr+s-1,tc+s-1);//對左上角子棋盤分割 49 cover(tr+s,tc,s,tr+s,tc+s-1);//對左下角子棋盤分割 50 cover(tr+s,tc+s,s,tr+s,tc+s);//對右下角子棋盤分割 51 } 52 else if(dr>=(tr+s)&&dc<(tc+s))//表示對當前輸入的棋盤而言,殘缺塊在左下角部分的子棋盤 53 { 54 count++; 55 bord[tr+s-1][tc+s-1]=count;//下面三個賦值語句是用③號模板覆蓋 56 bord[tr+s-1][tc+s]=count; 57 bord[tr+s][tc+s]=count; 58 cover(tr+s,tc,s,dr,dc); 59 60 cover(tr,tc,s,tr+s-1,tc+s-1); 61 cover(tr,tc+s,s,tr+s-1,tc+s); 62 cover(tr+s,tc+s,s,tr+s,tc+s); 63 } 64 else if(dr>=(tr+s)&&dc>=(tc+s))//表示對當前輸入的棋盤而言,殘缺塊在右下角部分的子棋盤 65 { 66 count++; 67 bord[tr+s-1][tc+s-1]=count;//下面三個賦值語句是用④號模板覆蓋 68 bord[tr+s-1][tc+s]=count; 69 bord[tr+s][tc+s-1]=count; 70 cover(tr+s,tc+s,s,dr,dc); 71 72 cover(tr,tc,s,tr+s-1,tc+s-1); 73 cover(tr,tc+s,s,tr+s-1,tc+s); 74 cover(tr+s,tc,s,tr+s,tc+s-1); 75 } 76 }
策略c:
先不停地分割,當分割到不能再分割時依次填充四個size=2的子棋盤,然后回溯到size=4的棋盤填充偽殘缺塊。
然后回溯到size=8,重復剛才的過程,依次處理另外三個size=4的子棋盤。
關鍵代碼如下:
完整代碼:
1 #include <iostream> 2 #include <iomanip> 3 4 using namespace std; 5 6 int num=1,arr[100][100]; 7 void Cover(int tr,int tc,int size,int dr,int dc) 8 { 9 if(size<2) return ; 10 int s; 11 s=size/2; 12 if(dr<(tr+s)&&dc<(tc+s)) 13 { 14 Cover(tr,tc,s,dr,dc); 15 Cover(tr,tc+s,s,tr+s-1,tc+s); 16 Cover(tr+s,tc,s,tr+s,tc+s-1); 17 Cover(tr+s,tc+s,s,tr+s,tc+s); 18 arr[tr+s-1][tc+s]=num; 19 arr[tr+s][tc+s-1]=num; 20 arr[tr+s][tc+s]=num; 21 num++; 22 } 23 else if(dr<(tr+s)&&dc>=(tc+s)) 24 { 25 Cover(tr,tc,s,tr+s-1,tc+s-1); 26 Cover(tr,tc+s,s,dr,dc); 27 Cover(tr+s,tc,s,tr+s,tc+s-1); 28 Cover(tr+s,tc+s,s,tr+s,tc+s); 29 arr[tr+s-1][tc+s-1]=num; 30 arr[tr+s][tc+s-1]=num; 31 arr[tr+s][tc+s]=num; 32 num++; 33 } 34 else if(dr>=(tr+s)&&dc<(tc+s)) 35 { 36 Cover(tr,tc,s,tr+s-1,tc+s-1); 37 Cover(tr,tc+s,s,tr+s-1,tc+s); 38 Cover(tr+s,tc,s,dr,dc); 39 Cover(tr+s,tc+s,s,tr+s,tc+s); 40 arr[tr+s-1][tc+s-1]=num; 41 arr[tr+s-1][tc+s]=num; 42 arr[tr+s][tc+s]=num; 43 num++; 44 } 45 else 46 { 47 Cover(tr,tc,s,tr+s-1,tc+s-1); 48 Cover(tr,tc+s,s,tr+s-1,tc+s); 49 Cover(tr+s,tc,s,tr+s,tc+s-1); 50 Cover(tr+s,tc+s,s,dr,dc); 51 arr[tr+s-1][tc+s-1]=num; 52 arr[tr+s-1][tc+s]=num; 53 arr[tr+s][tc+s-1]=num; 54 num++; 55 } 56 } 57 58 int main() 59 { 60 int k,x,y; 61 int temp=1; 62 cin>>k>>x>>y; 63 arr[x][y]=0; 64 for(int i=0;i<k;i++) 65 temp=temp*2; 66 Cover(0,0,temp,x,y); 67 for(int a=0;a<temp;a++) 68 { 69 for(int b=0;b<temp;b++) 70 { 71 cout<<setw(3)<<arr[a][b]; 72 } 73 cout<<endl; 74 } 75 return 0; 76 }
本問題可以參考:http://www.cnblogs.com/kahreman/archive/2011/08/08/2130613.html