首页 > 代码库 > 分治与递归-棋盘覆盖问题

分治与递归-棋盘覆盖问题

  在一个2^k×2^k个方格组成的棋盘中,若有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一个特殊棋盘.显然特殊方格在棋盘上出现的位置有4^k种情形.因而对任何k≥0,有4^k种不同的特殊棋盘.
     下图–图(1)中的特殊棋盘是当k=3时16个特殊棋盘中的一个:

技术分享

图(1)

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

技术分享

 

容易忽视的地方:棋盘分割以后,坐标会发生改变,所以要记录棋盘左上角的方格坐标以推得其他信息

注意的地方    :递归函数单次完成的任务:判断表格的左上角是不是特殊坐标 ,是则继续递归,不是,则覆盖表格的左上角的右下角,然后递归

                                                             判断表格的右上角是不是特殊坐标 ,是则继续递归,不是,则覆盖表格的右上角的左下角,然后递归

                                                             判断表格的左下角是不是特殊坐标 ,是则继续递归,不是,则覆盖表格的左下角的右上角,然后递归

                                                             判断表格的右下角是不是特殊坐标 ,是则继续递归,不是,则覆盖表格的左上角的左上角,然后递归

                                                             (递归的意思是 选定好初始值,然后继续执行这个函数,在单次完成时,不用关心)

 

所以递归函数有两个部分:一个部分是单次函数功能实现的部分(是特殊位置,不处理,不是特殊位置,为特定的点赋值)

                                      一个是上一个函数递推到下一个函数的部分( 继续递归)

 

所以说,继续递归出现的位置非常重要。

什么时候 继续递归?  分治的时候,分割的时候,由大问题过渡到小问题的时候,(比如找到特殊位置的时候,这时候我们已经做完了对大表的操作,接下来的操作是分割棋盘,所以继续递归)

 

                        判断该递归是不是符合要求,就看它能不能解决第一次的分治,由于分治的小问题与大问题解法相同,所以接下来递归只要保证初始值不出错。

 //棋盘覆盖问题  
/* 
(tr,tc)是棋盘左上角的方格坐标 
(dr,dc)是特殊方格所在的坐标 
size是棋盘的行数和列数  
*/   
#include<iostream>  
using namespace std;  
int board[1025][1025];  
static int tile = 1;  
  
void ChessBoard(int tr,int tc,int dr,int dc,int size)  
{  
    if(size==1) return ;//递归边界   
      
    int t=tile++;//L型骨牌号,t是骨牌的值,一个值代表一个骨牌
    int s=size/2;//分割棋盘,s是分割后1/4正方形的边长   
    //覆盖左上角子棋盘   
    if(dr<tr+s && dc<tc+s)  //判断坐标的通式
        ChessBoard(tr,tc,dr,dc,s);//特殊方格在此棋盘中   
    else //此棋盘中无特殊方格,用t号L型骨牌覆盖右下角   
    {  
        board[tr+s-1][tc+s-1]=t;  
        //覆盖其余方格   
        ChessBoard(tr,tc,tr+s-1,tc+s-1,s);  
    }  
    //覆盖右上角子棋盘   
    if(dr<tr+s && dc>=tc+s)  
        ChessBoard(tr,tc+s,dr,dc,s);//特殊方格在此棋盘中  
    else //此棋盘中无特殊方格,用t号L型骨牌覆盖左下角   
    {  
        board[tr+s-1][tc+s]=t;  
        //覆盖其余方格   
        ChessBoard(tr,tc+s,tr+s-1,tc+s,s);  
    }  
    //覆盖左下角子棋盘   
    if(dr>=tr+s && dc<tc+s)//特殊方格在此棋盘中  
        ChessBoard(tr+s,tc,dr,dc,s);  
    else //此棋盘中无特殊方格,用t号L型骨牌覆盖右上角   
    {  
        board[tr+s][tc+s-1]=t;  
        //覆盖其余方格   
        ChessBoard(tr+s,tc,tr+s,tc+s-1,s);  
    }  
    //覆盖右下角子棋盘   
    if(dr>=tr+s && dc>=tc+s)//特殊方格在此棋盘中  
        ChessBoard(tr+s,tc+s,dr,dc,s);  
    else //此棋盘中无特殊方格,用t号L型骨牌覆盖左上角   
    {  
        board[tr+s][tc+s]=t;  
        //覆盖其余方格   
        ChessBoard(tr+s,tc+s,tr+s,tc+s,s);  
    }  
}  
  
int main()  
{  
    int i,j;  
    int k;  
    while(cin>>k)  
    {  
        int size = 1<<k;  
        int x,y;    
        cin>>x>>y;    
        board[x][y]=0;  
        ChessBoard(0, 0, x, y, size);  
        for(i=0; i<size; i++)  
        {  
            for(j = 0; j < size; j++)  
               cout<< board[i][j]<<"\t";  
            cout<<"\n";  
        }  
    }  
    return 0;  
}  

 

 

 

  1.  //棋盘覆盖问题  
  2. /* 
  3. (tr,tc)是棋盘左上角的方格坐标 
  4. (dr,dc)是特殊方格所在的坐标 
  5. size是棋盘的行数和列数  
  6. */   

分治与递归-棋盘覆盖问题