棋盘覆盖问题

问题描述:

      在一个2^k×2^k个方格组成的棋盘中,若有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一个特殊棋盘.显然特殊方格在棋盘上出现的位置有4^k种情形.因而对任何k≥0,有4^k种不同的特殊棋盘.

     下图–图(1)中的特殊棋盘是当k=3时16个特殊棋盘中的一个:

残缺棋盘的覆盖问题_2d

图(1)

题目要求在棋盘覆盖问题中,要用下图-图(2)所示的4种不同形态的L型骨牌覆盖一个给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖.

残缺棋盘的覆盖问题_i++_02

图(2)

题目输入k,输出棋盘覆盖的顺序。覆盖策略可以自己选择。

分析:

这个题其实可以有不同的覆盖顺序。比如:(下图中的数字表示依次覆盖的顺序)

残缺棋盘的覆盖问题_棋盘覆盖_03残缺棋盘的覆盖问题_棋盘覆盖_04残缺棋盘的覆盖问题_i++_05

策略a 策略b 策略c

策略a:

不停地分割寻找残缺块所在区域,然后在残缺块周围填充第一块(这个时候size=2);然后回溯一层,填充伪残缺块(这个时候size=4);然后对当前size=4的另外三个子棋盘依次填充(含残缺块的子棋盘当然不再填充了。)。

填充完size==4的棋盘后,回溯到size=8的棋盘(假如存在size=8的棋盘的话呵呵),重复刚才的过程:先填充size=8这个棋盘的伪残缺块,然后填充另外的三个子棋盘。……

关键代码如下:

残缺棋盘的覆盖问题_2d_06

完整代码:


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)

然后依次处理当前层的四个子棋盘:分割——填充伪残缺块——处理更小的子棋盘。

整个程序重复该过程,最终完成填充任务。

关键代码如下:

残缺棋盘的覆盖问题_#include_07

完整代码:


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的子棋盘。

关键代码如下:

残缺棋盘的覆盖问题_2d_08


完整代码:


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 }