棋盘覆盖问题

在一个2^k×2^k (k≥0)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格。显然,特殊方格在棋盘中可能出现的位置有4^k种,因而有4^k种不同的棋盘,图4.10(a)所示是k=2时16种棋盘中的一个。棋盘覆盖问题(chess cover problem)要求用图4.10(b)所示的4种不同形状的L型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
棋盘覆盖问题_第1张图片
解法思路:我们将一个完整的棋盘分解成4个2^(k-1) ×2^(k-1)的小的棋盘,那么必然有一个含有这个原始的阴影部分,其他的三个小棋盘必然不含有。
而这些不含有阴影部分的棋盘,其交界处必然可以使用这四种不同的L型骨牌中的一个来覆盖,那么我们使用满足条件的这个骨牌来覆盖的时候,这三个小的棋盘又必然变成了这个大问题的三个小问题。这样我们就会自然想到使用分治法解决。当棋盘的大小为2的时候自然可以直接覆盖。
PS:关于这个问题为什么总是有解,其实很简单。如果对于n=k的规模是有解,那么我们使用分治法来处理n=k+1的时候可以看成处理4个小的n'=k时的结果的综合。又n=2时有解,则可以使用类似数学归纳法的方法证明此问题总是有解。
#include
#include
using namespace std;
#define M 10000
int map[M][M];
int bad;
void fill(int stx,int sty,int size,int x,int y)
{
	int i,j;
	if(size==2)
	{
		bad=bad+1;
		for(i=stx;i<=stx+size-1;i++)
			for(j=sty;j<=sty+size-1;j++)
				if(map[i][j]==-1)
					map[i][j]=bad;
		return ;
	}
	size=size/2;
	bad=bad+1;
	int temp=bad;//尤其注意此局部变量的使用,每次调用fill函数就意味着用一个新的L型板子,bad可以区分各个板子
	//如果不适用一个局部变量,fill过程类似深搜每搜索一次bad+1,那么对同一块板子其他格子赋值出错
	if(x<=stx+size-1&&y<=sty+size-1)
		fill(stx,sty,size,x,y);
	else {
		map[stx+size-1][sty+size-1]=temp;
		fill(stx,sty,size,stx+size-1,sty+size-1);
	}
	if(x<=stx+size-1&&y>=sty+size)
		fill(stx,sty+size,size,x,y);
	else {
		map[stx+size-1][sty+size]=temp;
		fill(stx,sty+size,size,stx+size-1,sty+size);
	}
	if(x>=stx+size&&y<=sty+size-1)
		fill(stx+size,sty,size,x,y);
	else {
		map[stx+size][sty+size-1]=temp;
		fill(stx+size,sty,size,stx+size,sty+size-1);
	}
	if(x>=stx+size&&y>=sty+size)
		fill(stx+size,sty+size,size,x,y);
	else {
		map[stx+size][sty+size]=temp;
		fill(stx+size,sty+size,size,stx+size,sty+size);
	}
}
int main()
{
	int n,len,x,y,i,j;
	cin>>n;
	while(n--)
	{
		cin>>len>>x>>y;
		bad=0;
		for(i=1;i<=len;i++)
			for(j=1;j<=len;j++)
				map[i][j]=-1;
		map[x][y]=0;
		fill(1,1,len,x,y);
		for(i=1;i<=len;i++)
		{
			for(j=1;j<=len;j++)
				cout<




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