殘缺棋盤的覆蓋問題


棋盤覆蓋問題   

問題描述:

      在一個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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM