棋盘覆盖问题(分治)

来源:互联网 发布:减速机 知乎 编辑:程序博客网 时间:2024/05/16 00:42

棋盘覆盖问题:

问题描述

现在有一个大小的棋盘,在棋盘内部有一只特别的棋子,输入的坐标为XY

要求尝试用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的棋盘覆盖问题了。

以此类推…

实际上,这就是我们算法里面常见的分治算法,将一个问题分成若干个小问题,问题之间相互不影响,通过解决所有子问题实现求出主问题的办法。

 

代码如下:

[cpp] view plain copy
print?
  1. #define  _CRT_SECURE_NO_WARNINGS  
  2. #include<iostream>  
  3. #include<cstdlib>  
  4. #include<cstring>  
  5. usingnamespacestd;  
  6. #defineMAX_SIZE100  
  7. intboard[MAX_SIZE][MAX_SIZE];  /*definecheckerboard MAXSIZE = 64*64 */  
  8. inttmp=1;  
  9.    
  10. intlocate(intdes_x,intdes_y,intlength,intx,inty)//指定棋子(des_x,des_y)的棋盘长度为length,左上角坐标为xy的位置  
  11. {  
  12.     /* 
  13.         只要将棋子所在区域标记为1234,用于判断与其他棋子的区域是否相同 
  14.     */  
  15.     if(des_x<length+x&&des_y<length+y)  
  16.         return1;  
  17.     if(des_x<length+x&&des_y>=length+y)  
  18.         return2;  
  19.     if(des_x>=length+x&&des_y<length+y)  
  20.         return3;  
  21.     if(des_x>=length+x&&des_y>=length+y)  
  22.         return4;  
  23.     return0;  
  24. }  
  25.    
  26. voidcheckboard(intlength,intx,inty)//棋盘长度为length,棋盘最左上角的坐标为xy  
  27. {  
  28.     if(length==2)  
  29.     {  
  30.         for(inti=x;i<x+length;i++)  
  31.         for(intj=y;j<y+length;j++)  
  32.         if(board[i][j]==-1)//是空,则直接覆盖  
  33.             board[i][j]=tmp;  
  34.         tmp++;  
  35.     }  
  36.     else  
  37.     {  
  38.         inti,j;  
  39.         intdir_x,dir_y;  
  40.         for(i=x;i<x+length;i++)  
  41.         for(j=y;j<y+length;j++)  
  42.         {  
  43.             if(board[i][j]!=-1)//找到非空棋子  
  44.             {  
  45.                 dir_x=i;  
  46.                 dir_y=j;  
  47.             }  
  48.         }  
  49.         length/=2;//下一次循环棋盘长度缩小为二分之一  
  50.         intmode=locate(dir_x,dir_y,length,x,y);//定位特殊棋子位置,此时(length+x,length+y)是中线  
  51.         for(i=x+length-1;i<=x+length;i++)//遍历分界线的四个棋子  
  52.         for(j=y+length-1;j<=x+length;j++)  
  53.         {  
  54.             if(locate(i,j,length,x,y)!=mode)//只要和特殊棋子不在同一区域就覆盖  
  55.                 board[i][j]=tmp;  
  56.         }  
  57.         tmp++;  
  58.         checkboard(length,x,y);  
  59.         checkboard(length,x,y+length);  
  60.         checkboard(length,x+length,y);  
  61.         checkboard(length,x+length,y+length);  
  62.     }  
  63. }  
  64. intmain(void)  
  65. {  
  66.     intsize,x,y,len;  
  67.     memset(board,-1,sizeof(board));  
  68.     cout<<"请输入棋盘大小的K值:"<<endl;  
  69.     cin>>len;  
  70.     size=(int)pow(2,len);  
  71.     cout<<"size = "<<size<<endl;  
  72.     cout<<"请输入特殊棋子的行坐标X(从0开始计算):";  
  73.     cin>>x;  
  74.     cout<<"请输入特殊棋子的列坐标y(从0开始计算):";  
  75.     cin>>y;  
  76.     board[x][y]=0;  
  77.     cout<<"x = "<<x<<" y = "<<y<<endl;  
  78.     checkboard(size,0,0);  
  79.    
  80.     for(inti=0;i<size;i++)  
  81.     {  
  82.         for(intj=0;j<size;j++)  
  83.         {  
  84.             cout<<board[i][j]<<"\t";  
  85.         }  
  86.         cout<<endl;  
  87.     }  
  88.     cout<<endl;  
  89.     system("pause");  
  90.     return0;  
  91. }  


0 0
原创粉丝点击