问题描述:在一个2k×2k (k≥0)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格。棋盘覆盖问题要求用图4.11(b)所示的4种不同形状的L型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
(a) k=2时的一种棋盘 (b) 4种不同形状的L型骨牌
算法思路:采用分治法,特殊方格必位于 4 个较小子棋盘之一中,其余 3 个子棋盘中无特殊方格。为了将这 3 个无特殊方格的子棋盘转化为特殊棋盘,我们可以用一个 L 型骨牌覆盖这 3 个较小的棋盘的汇合处,如下图所示,这 3 个子棋盘上被 L 型骨牌覆盖的方格就成为该棋盘上的特殊方格,从而将原问题化为 4 个较小规模的棋盘覆盖问题。递归的使用 这种分割,直至棋盘简化为 1x1 棋盘。
C语言代码如下(在devC++编译运行通过):
#include <stdio.h>
#include <stdlib.h>
int flag=1;
int board[100][100];
/*****************************************************
* 递归方式实现棋盘覆盖算法
* 输入参数:
* tr--当前棋盘左上角的行号
* tc--当前棋盘左上角的列号
* dr--当前特殊方格所在的行号
* dc--当前特殊方格所在的列号
* size:当前棋盘的:2^k
*****************************************************/
void chessBoard(int tr,int tc,int dr,int dc,int size)
{
if(size==1)
return;
int t=flag++;
int s=size/2;
if(dr<tr+s && dc<tc+s) //特殊方格在左上角子棋盘
chessBoard(tr,tc,dr,dc,s);
else // 不在此棋盘,将此棋盘右下角设为相应的骨牌号
{
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 // 不在此棋盘,将此棋盘左下角设为相应的骨牌号
{
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 // 不在此棋盘,将此棋盘右上角设为相应的骨牌号
{
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 // 不在此棋盘,将此棋盘左上角设为相应的骨牌号
{
board[tr+s][tc+s]=t;
chessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}
int main()
{
int size,i,j;
printf("输入棋盘的size(大小必须是2的n次幂): ");
scanf("%d",&size);
int x,y;
printf("输入特殊方格位置的坐标: ");
scanf("%d%d",&x,&y);
chessBoard(0,0,x,y,size);
for(i=0;i<size;i++){
for(j=0;j<size;j++)
printf("%-4d", board[i][j]);
printf("\n");
}
system("pause");
return 0;
}