算法竞赛入门 LRJ 棋盘覆盖问题
在一个 2^k * 2^k 个方格组成的棋盘中,若恰有一个方格与其它方格不同,则称该方格为一特殊方格,称该棋盘为一特殊棋盘。显然特殊方格在棋盘上出现的位置有 4^k 种情形。因而对任何 k>=0 ,有 4^k 种不同的特殊棋盘。下图所示的特殊棋盘为 k=2 时 16 个特殊棋盘中的一个。
在棋盘覆盖问题中,要用下图中 4 中不同形态的 L 型骨牌覆盖一个给定的特殊棋牌上除特殊方格以外的所有方格,且任何 2 个 L 型骨牌不得重叠覆盖。易知,在任何一个 2^k * 2^k 的棋盘中,用到的 L 型骨牌个数恰为 (4^k-1)/3 。现给出棋盘的大小和特殊方格所在的位置,请找出这种棋盘。
【样例输入】
1
0 0
【样例输出】
0 1
1 1
题解: 2^k * 2^k 的棋盘分割成4个 2^(k-1) * 2^(k-1) 的小棋盘,分别在左上,右上,左下,右下。判断特殊方格所在的小棋盘,在没有特殊方格的小棋盘做如下处理:
左上小棋盘: 在其右下角填一个特殊方格。
右上小棋盘: 在其左下角填一个特殊方格。
左下小棋盘: 在其右上角填一个特殊方格。
右下小棋盘: 在其左上角填一个特殊方格。
没有特殊方格的三个小棋盘填方格后,其就相当于填一个L骨牌。
那么在四个小棋盘中都有一个特殊方格,问题缩小为:在2^(k-1) * 2^(k-1) 的小棋盘填L骨牌。
由而分治处理。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
#include<queue>
#include<cmath>
#include<algorithm>
#include<deque>
typedef long long LL;
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
const int INF=0x3f3f3f3f;
const int N = 110;
int board[N][N];
int type; // L骨牌的编号
void init()
{
memset(board,0,sizeof(board));
type = 1;
}
// br bc 棋盘左上角位置
// x y 特殊方格位置
void slove(int br,int bc,int x,int y,int Size)
{
if(Size == 1)
return ;
int s = Size/2;
int t = type++;
// 处理左上
if(br+s > x && bc+s > y) //有特殊方格
slove(br,bc,x,y,s);
else //没有特殊方格
{
board[br+s-1][bc+s-1] = t;
slove(br,bc,br+s-1,bc+s-1,s);
}
// 处理右上
if(br+s > x && bc+s <= y) //有特殊方格
slove(br,bc+s,x,y,s);
else //没有特殊方格
{
board[br+s-1][bc+s] = t;
slove(br,bc+s,br+s-1,bc+s,s);
}
// 处理左下
if(br+s <= x && bc+s > y) //有特殊方格
slove(br+s,bc,x,y,s);
else //没有特殊方格
{
board[br+s][bc+s-1] = t;
slove(br+s,bc,br+s,bc+s-1,s);
}
// 处理右下
if(br+s <= x && bc+s <= y) //有特殊方格
slove(br+s,bc+s,x,y,s);
else //没有特殊方格
{
board[br+s][bc+s] = t;
slove(br+s,bc+s,br+s,bc+s,s);
}
}
int main()
{
init();
int k,x,y;
scanf("%d",&k);
int Size = 1<<k;
//x , y 特殊方格的位置
scanf("%d%d",&x,&y);
slove(0,0,x,y,Size);
for(int i = 0; i < Size; i++)
{
for(int j = 0; j < Size; j++)
printf("%d ",board[i][j]);
printf("\n");
}
return 0;
}