棋盘覆盖问题

在一个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型骨牌不得重叠覆盖。

解法思路:我们将一个完整的棋盘分解成4个2^(k-1) ×2^(k-1)的小的棋盘,那么必然有一个含有这个原始的阴影部分,其他的三个小棋盘必然不含有。
而这些不含有阴影部分的棋盘,其交界处必然可以使用这四种不同的L型骨牌中的一个来覆盖,那么我们使用满足条件的这个骨牌来覆盖的时候,这三个小的棋盘又必然变成了这个大问题的三个小问题。这样我们就会自然想到使用分治法解决。当棋盘的大小为2的时候自然可以直接覆盖。
PS:关于这个问题为什么总是有解,其实很简单。如果对于n=k的规模是有解,那么我们使用分治法来处理n=k+1的时候可以看成处理4个小的n'=k时的结果的综合。又n=2时有解,则可以使用类似数学归纳法的方法证明此问题总是有解。
#include<iostream>
#include<iomanip>
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<<setw(3)<<map[i][j];
			cout<<endl;
		}
	}
	return 0;
}





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值