残缺棋盘的覆盖问题

简介: 棋盘覆盖问题   问题描述:      在一个2^k×2^k个方格组成的棋盘中,若有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一个特殊棋盘.显然特殊方格在棋盘上出现的位置有4^k种情形.因而对任何k≥0,有4^k种不同的特殊棋盘.     下图–图(1)中的特殊棋盘是当k=3时16个特殊棋盘中的一个:图(1)题目要求在棋盘覆盖问题中,要用下图-图(2)所示的4种不同形态的L型骨牌覆盖一个给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖.图(2)题目输入k,输出棋盘覆盖的顺序。

棋盘覆盖问题   

问题描述:

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

相关文章
|
7月前
|
存储 程序员 C语言
扫雷?拿来吧你(递归展开+坐标标记)
扫雷?拿来吧你(递归展开+坐标标记)
|
7月前
|
存储 算法 编译器
扫雷游戏棋盘的打印,判断输赢,深度分析
扫雷游戏棋盘的打印,判断输赢,深度分析
|
7月前
|
C++
[C++/PTA] 判断一个点是否在一个圆的内部
[C++/PTA] 判断一个点是否在一个圆的内部
83 0
|
机器学习/深度学习 算法 测试技术
C++前缀和算法的应用:用地毯覆盖后的最少白色砖块 原理源码测试用例
C++前缀和算法的应用:用地毯覆盖后的最少白色砖块 原理源码测试用例
三角形判断
三角形判断
86 0
学C的第二十四天【练习:1. 打印菱形;2. 打印自幂数;3. 求Sn=a+aa..n项之和;4. 喝汽水问题;5. 调整数组使奇数位于偶数前面;6. 打印X形图案;7……;8……;9……;10……】-2
5. 调整数组使奇数全部都位于偶数前面 题目: 输入一个整数数组,实现一个函数, 来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分, 所有偶数位于数组的后半部分。
130 0
|
机器学习/深度学习 Python
【每周一坑】输出三角形
如果输出固定长度对你来说太简单了,可以增加一个输入 n(n为正整数且 n>3),作为输出三角形第一行星号的数量。
LeetCode 1812. 判断国际象棋棋盘中一个格子的颜色
给你一个坐标 coordinates ,它是一个字符串,表示国际象棋棋盘中一个格子的坐标。下图是国际象棋棋盘示意图。
136 0
|
前端开发 容器
每日一题:如何判断一个元素是否在可视区域中?
每日一题:如何判断一个元素是否在可视区域中?
366 0
每日一题:如何判断一个元素是否在可视区域中?