棋盤覆蓋
在一個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;
}