棋盘覆盖问题:
问题描述:
现在有一个大小的棋盘,在棋盘内部有一只特别的棋子,输入的坐标为X和Y。
要求尝试用4种不同类型的骨牌将棋盘覆盖,要求,骨牌之间不得重叠,并且骨牌不得覆盖特殊棋子,每个骨牌占用3个单位大小,形状如下。
棋盘假设如下:
思路分析:
对于这种题目,我们先从k=0开始分析:
当k=0的时候,棋盘大小为1,整个棋盘被特殊棋子覆盖。
当k=1的时候,棋盘大小为4,棋盘可以被一个骨牌外加一个特殊棋子覆盖
假设如下:
当k=2的时候,棋盘大小为16,棋盘可以被这样覆盖
当k=3的时候,棋盘可以被这样覆盖
第一次我写到这里的时候就发现,因为这个棋盘是
假设当我k=2的时候,棋盘大小是16,那么我可以将棋盘平均分成四块,每块大小是4,那么特殊棋子必须落在其中一个区域,这是,只要我让每一个区域的大小从4变成3,我就可以填满整个棋盘,所以可以选择在分界线填充骨牌。如下图:
那么,剩下的区域我都有相应的骨牌填充。
当k=3的时候,我们可以先把64的空间平均分成16*4,我们已经有一个区域有一个特殊棋子了,接下来,我们要把骨牌放在分界线上,让骨牌每一个单位成为新的假设的“特殊棋子”,这时候问题就变成了求4个棋盘大小为16的棋盘覆盖问题了。
以此类推…
实际上,这就是我们算法里面常见的分治算法,将一个问题分成若干个小问题,问题之间相互不影响,通过解决所有子问题实现求出主问题的办法。
代码如下:
- #define _CRT_SECURE_NO_WARNINGS
- #include<iostream>
- #include<cstdlib>
- #include<cstring>
- usingnamespacestd;
- #defineMAX_SIZE100
- intboard[MAX_SIZE][MAX_SIZE]; /*definecheckerboard MAXSIZE = 64*64 */
- inttmp=1;
- intlocate(intdes_x,intdes_y,intlength,intx,inty)//指定棋子(des_x,des_y)的棋盘长度为length,左上角坐标为xy的位置
- {
- /*
- 只要将棋子所在区域标记为1234,用于判断与其他棋子的区域是否相同
- */
- if(des_x<length+x&&des_y<length+y)
- return1;
- if(des_x<length+x&&des_y>=length+y)
- return2;
- if(des_x>=length+x&&des_y<length+y)
- return3;
- if(des_x>=length+x&&des_y>=length+y)
- return4;
- return0;
- }
- voidcheckboard(intlength,intx,inty)//棋盘长度为length,棋盘最左上角的坐标为xy
- {
- if(length==2)
- {
- for(inti=x;i<x+length;i++)
- for(intj=y;j<y+length;j++)
- if(board[i][j]==-1)//是空,则直接覆盖
- board[i][j]=tmp;
- tmp++;
- }
- else
- {
- inti,j;
- intdir_x,dir_y;
- for(i=x;i<x+length;i++)
- for(j=y;j<y+length;j++)
- {
- if(board[i][j]!=-1)//找到非空棋子
- {
- dir_x=i;
- dir_y=j;
- }
- }
- length/=2;//下一次循环棋盘长度缩小为二分之一
- intmode=locate(dir_x,dir_y,length,x,y);//定位特殊棋子位置,此时(length+x,length+y)是中线
- for(i=x+length-1;i<=x+length;i++)//遍历分界线的四个棋子
- for(j=y+length-1;j<=x+length;j++)
- {
- if(locate(i,j,length,x,y)!=mode)//只要和特殊棋子不在同一区域就覆盖
- board[i][j]=tmp;
- }
- tmp++;
- checkboard(length,x,y);
- checkboard(length,x,y+length);
- checkboard(length,x+length,y);
- checkboard(length,x+length,y+length);
- }
- }
- intmain(void)
- {
- intsize,x,y,len;
- memset(board,-1,sizeof(board));
- cout<<"请输入棋盘大小的K值:"<<endl;
- cin>>len;
- size=(int)pow(2,len);
- cout<<"size = "<<size<<endl;
- cout<<"请输入特殊棋子的行坐标X(从0开始计算):";
- cin>>x;
- cout<<"请输入特殊棋子的列坐标y(从0开始计算):";
- cin>>y;
- board[x][y]=0;
- cout<<"x = "<<x<<" y = "<<y<<endl;
- checkboard(size,0,0);
- for(inti=0;i<size;i++)
- {
- for(intj=0;j<size;j++)
- {
- cout<<board[i][j]<<"\t";
- }
- cout<<endl;
- }
- cout<<endl;
- system("pause");
- return0;
- }
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdlib>
#include<cstring>
usingnamespacestd;
#defineMAX_SIZE100
intboard[MAX_SIZE][MAX_SIZE]; /*definecheckerboard MAXSIZE = 64*64 */
inttmp=1;
intlocate(intdes_x,intdes_y,intlength,intx,inty)//指定棋子(des_x,des_y)的棋盘长度为length,左上角坐标为xy的位置
{
/*
只要将棋子所在区域标记为1234,用于判断与其他棋子的区域是否相同
*/
if(des_x<length+x&&des_y<length+y)
return1;
if(des_x<length+x&&des_y>=length+y)
return2;
if(des_x>=length+x&&des_y<length+y)
return3;
if(des_x>=length+x&&des_y>=length+y)
return4;
return0;
}
voidcheckboard(intlength,intx,inty)//棋盘长度为length,棋盘最左上角的坐标为xy
{
if(length==2)
{
for(inti=x;i<x+length;i++)
for(intj=y;j<y+length;j++)
if(board[i][j]==-1)//是空,则直接覆盖
board[i][j]=tmp;
tmp++;
}
else
{
inti,j;
intdir_x,dir_y;
for(i=x;i<x+length;i++)
for(j=y;j<y+length;j++)
{
if(board[i][j]!=-1)//找到非空棋子
{
dir_x=i;
dir_y=j;
}
}
length/=2;//下一次循环棋盘长度缩小为二分之一
intmode=locate(dir_x,dir_y,length,x,y);//定位特殊棋子位置,此时(length+x,length+y)是中线
for(i=x+length-1;i<=x+length;i++)//遍历分界线的四个棋子
for(j=y+length-1;j<=x+length;j++)
{
if(locate(i,j,length,x,y)!=mode)//只要和特殊棋子不在同一区域就覆盖
board[i][j]=tmp;
}
tmp++;
checkboard(length,x,y);
checkboard(length,x,y+length);
checkboard(length,x+length,y);
checkboard(length,x+length,y+length);
}
}
intmain(void)
{
intsize,x,y,len;
memset(board,-1,sizeof(board));
cout<<"请输入棋盘大小的K值:"<<endl;
cin>>len;
size=(int)pow(2,len);
cout<<"size = "<<size<<endl;
cout<<"请输入特殊棋子的行坐标X(从0开始计算):";
cin>>x;
cout<<"请输入特殊棋子的列坐标y(从0开始计算):";
cin>>y;
board[x][y]=0;
cout<<"x = "<<x<<" y = "<<y<<endl;
checkboard(size,0,0);
for(inti=0;i<size;i++)
{
for(intj=0;j<size;j++)
{
cout<<board[i][j]<<"\t";
}
cout<<endl;
}
cout<<endl;
system("pause");
return0;
}