分治法——棋盘覆盖问题

输入:

在一个2^k * 2^k(k>0)个方格中,有一个方格与其他方格不同(如图1

                    分治法——棋盘覆盖问题

 

(图1

然后用以下四种L型骨牌(如图2)覆盖除特殊方格外的其他棋盘,且任何两个L型骨牌不得重复

                         (图2

输出:

用这四种L型骨牌覆盖除特殊方格(0表示特殊方格)外的所有方格,如图3所示:

2

2

3

3

2

1

0

3

4

1

1

5

4

4

5

5

                             (图3

算法设计:

运用分治法的思想,当k>0时,把2^k * 2^k方格分解成4个2^k -1* 2^k-1(k>0)个方格,其中特殊方格位于4个中的一个,构造剩下没特殊方格三个子棋盘,将他们中的也假一个方格设为特殊方格。如果是:

左上角的子棋盘(若不存在特殊方格)----则将该子棋盘右下角的那个方格假设为特殊方格
右上角的子棋盘(若不存在特殊方格)----则将该子棋盘左下角的那个方格假设为特殊方格
左下角的子棋盘(若不存在特殊方格)----则将该子棋盘右上角的那个方格假设为特殊方格
右下角的子棋盘(若不存在特殊方格)----则将该子棋盘左上角的那个方格假设为特殊方格

上面四种情况必定只有三个成立,那三个假设的特殊方格刚好构成一个L型骨架,并给它们作上相同的标记。这样四个子棋盘就分别都和原来的大棋盘类似,这样就可以用递归算法解决。

C++代码:

#include  < iostream >
using   namespace  std;
int  board[ 32 ][ 32 ];

//  tr, tc: 棋盘左上角的下标
//  dr, dc: 特殊方格的下标
//  size = 2 ^ k   棋盘的大小
void  chessboard( int  tr,  int  tc,  int  dr,  int  dc,  int  size)
{
    
if (size  == 1  )  return ;
    
int  half_size;
    
static   int  num = 1 ;
    
int  t = num ++ ;
    half_size 
=  size  /   2 ;   
   
    
if (dr  <  tr  +  half_size  &&  dc  <  tc  +  half_size)  // 特殊方格在左上角子棋盘
    {
       chessboard(tr, tc, dr, dc, half_size); 
    }
    
else     //  不在此棋盘,将此棋盘右下角设为相应的骨牌号
    {
       board[tr 
+  half_size  -   1 ][tc  +  half_size  -   1 =  t;
       chessboard(tr, tc, tr 
+  half_size  -   1 , tc  +  half_size  -   1 , half_size);
    }
   
    
if (dr  <  tr  +  half_size  &&  dc  >=  tc  +  half_size)  // 特殊方格在右上角子棋盘
    {
       chessboard(tr, tc 
+  half_size, dr, dc, half_size);
    }
    
else    //  不在此棋盘,将此棋盘左下角设为相应的骨牌号
    {
       board[tr 
+  half_size  -   1 ][tc  +  half_size]  =  t;
       chessboard(tr, tc 
+  half_size, tr  +  half_size  -   1 , tc  +  half_size, half_size);
    }
   
    
if (dr  >=  tr  +  half_size  &&  dc  <  tc  +  half_size)  // 特殊方格在左下角子棋盘
    {
       chessboard(tr 
+  half_size, tc, dr, dc, half_size);
    }
    
else    //  不在此棋盘,将此棋盘右上角设为相应的骨牌号
    {
       board[tr 
+  half_size][tc  +  half_size  -   1 =  t;
       chessboard(tr 
+  half_size, tc, tr  +  half_size, tc  +  half_size  -   1 , half_size);
 }
   
    
if (dr  >=  tr  +  half_size  &&  dc  >=  tc  +  half_size)  // 特殊方格在右下角子棋盘
    {
       chessboard(tr 
+  half_size, tc  +  half_size, dr, dc, half_size);
    }
    
else     //  不在此棋盘,将此棋盘右下角设为相应的骨牌号
    {
       board[tr 
+  half_size][tc  +  half_size]  =  t;
       chessboard(tr 
+  half_size, tc  +  half_size, tr  +  half_size, tc  +  half_size, half_size);
    }   
}

void  main()
{   
    
int  i,j,size;
    cout
<< " 输入棋盘的size(大小必须是2的n次方):  " ;   
    cin
>> size;  
    
int  x,y;  
    cout
<< " 输入特殊方格位置的坐标:  " ;    
    cin
>> x >> y;  
    board[x][y]
= 0 ; // 特殊方格初始化为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 " ;
    }
}

你可能感兴趣的:(分治法)