棋盘覆盖
在一个2^k * 2^k 个方格组成的棋盘中,若恰好有一个方格与其他方格不同,则称该房改为一特殊方格,且称该棋盘为一特殊棋盘。显然特殊方格在棋盘上出现的位置有4^k种情况。
在棋盘覆盖问题中,要用如下图所示的4种不同形态的L型骨牌覆盖一个给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重复覆盖。可知,在任何一个2^k * 2^k的棋盘覆盖中,用到的L型骨牌的个数恰为(4^k - 1)/3。
特殊棋盘图
算法思想:用分治策略,可以设计解棋盘覆盖为题的一个算法。当k > 0时,将2^k * 2^k棋盘分割为4个2^k-1 * 2^k-1字棋盘,特殊方格必位于4个子棋盘之一中,其余3个子棋盘中无特殊方格。为了这3个无特殊方格的子棋盘转化为特殊棋盘,我们用一个L型骨牌覆盖这3个子棋盘的汇合处,如下图:
从而将原问题转化为4个子棋盘覆盖问题。递归的使用这种分割,直至棋盘简化为1*1棋盘。
实现这种分治策略的算法可描述如下:
#include <iostream>
#include <cstring>
using namespace std;
const int MAX_SIZE = 10;
int tite = 1;
int board[MAX_SIZE][MAX_SIZE];
/*
函数名称:ChessBoard
函数功能:实现2^k * 2^k 的棋盘覆盖
函数参数:
tr:棋盘左上角的行号
tc:棋盘左上角的列号
dr:特殊方格的行号
dc:特殊方格的列号
size:棋盘规格大小
tite:L型骨牌的编号 其初始值为1 全局变量
返回值:无
*/
void ChessBoard(int tr, int tc, int dr, int dc, int size)
{
if(size == 1)
return ;
int t = tite++;
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 + s - 1), 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 n = 0;
while(cin >> n)
{
memset(board, -1, sizeof(board));
board[2][2] = 0;
ChessBoard(0, 0, 2, 2, n);
for(int i = 0;i < n;++i)
{
for(int j = 0; j < n; ++j)
cout << board[i][j];
cout << endl;
}
}
return 0;
}