棋盘覆盖问题
问题描述:
在一个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