棋盤覆蓋
(一)原理介紹
在一個2^k * 2^k個方格組成的棋盤中,恰有一個方格與其它方格不同,稱該方格爲一特殊方格,且稱該棋盤爲以特殊棋盤。
在棋盤覆蓋問題中,要用圖示的4種不同形態的L型骨牌覆蓋給定的特殊棋盤上除特殊方格之外的所有方格,且任何2個L型骨牌不得重疊覆蓋。
當k>0時,將2^k * 2^k棋盤分割爲4個2^(k-1) * 2^(k - 1)子棋盤,如下圖所示。特殊方格必位於4個較小子棋盤之一種,其餘3個子棋盤中無特殊方格。爲了將這3個無特殊方格的子棋盤轉化爲特殊棋盤,可以用一個L型骨牌覆蓋這3個較小棋盤的會合處,如下圖所示。從而將原問題轉化爲4個較小規模的棋盤覆蓋問題。遞歸地使用這種分割,直至棋盤簡化爲棋盤1*1。
爲了更加清楚瞭解這個原理,下面引用:http://www.ezloo.com/2008/04/chessboard_cover.html
這裏我們用分治法解決該問題。分治法是把一個規模很大的問題分解爲多個規模較小的類似的子問題,然後遞歸地解決所有子問題,最後再由子問題的解決得到原問題的解決。
【解題思路】
將2^k * 2^k的棋盤,先分成相等的四塊子棋盤,其中特殊方格位於四個中的一個,構造剩下沒特殊方格的三個字棋盤,將它們中的也假設一個方格爲特殊方格。如果是:
左上角的子棋盤(若不存在特殊方格):則將該子棋盤右下角的那個方格假設爲特殊方格;
右上角的子棋盤(若不存在特殊方格):則將該子棋盤左下角的那個方格假設爲特殊方格;
左下角的子棋盤(若不存在特殊方格):則將該子棋盤右上角的那個方格假設爲特殊方格;
右下角的子棋盤(若不存在特殊方格):則將該子棋盤左上角的那個方格假設爲特殊方格;
當然,上面四種情況,只可能且必定只有三種成立,那三個假設的特殊方格剛好構成一個L型骨牌,我們可以給它們作上相同的標誌。這樣四個子棋盤就分別都和原來的大棋盤類似,我們就可以用遞歸的算法解決了。
(二)代碼實現
#include <stdio.h>
#include <stdlib.h>
#define SIZE 4
static int title = 1; //title表示L型骨牌的編號
static int board[SIZE][SIZE];
/**
* 功能:棋盤覆蓋
* @param tr表示棋盤左上角行號
* @param tc表示棋盤左上角列號
* @param dr表示特殊棋盤的行號
* @param dc表示特殊棋盤的列號
* @param size = 2^k
* 棋盤的規格爲2^k * 2^k
**/
void ChessBoard(int tr, int tc, int dr, int dc, int size)
{
if(1 == size)
{
return;
}
int t = title++; //L型骨牌號
int s = size / 2; //分割棋盤
//覆蓋左上角子棋盤
if(dr < tr + s && dc < tc + s)
{
//特殊方格在此棋盤中
ChessBoard(tr, tc, dr, dc, s);
}
else
{
//此棋盤無特殊方格
//用t號L型骨牌覆蓋右下角
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
{
//此子棋盤中無特殊方格
//用t號L型骨牌覆蓋左下角
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, dr, dc, s);
}
else
{
//用t號L型骨牌覆蓋右上角
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
{
//用t號L型骨牌覆蓋左上角
board[tr + s][tc + s] = t;
//覆蓋其餘方格
ChessBoard(tr + s, tc + s, tr + s, tc + s, s);
}
}
//打印
void ChessPrint()
{
int i;
int j;
for(i = 0; i < SIZE; i++)
{
for(j = 0; j < SIZE; j++)
{
printf("%d ", board[i][j]);
}
printf("n");
}
}
int main(int argc, char **argv)
{
//方便測試,假設特殊方格位置在第三行第三列
ChessBoard(0, 0, 2, 2, SIZE);
ChessPrint();
return 0;
}
—————————————————————————————————
本文原創自Slience的csdn技術博客。
本博客所有原創文章請以鏈接形式註明出處。
歡迎關注本技術博客,本博客的文章會不定期更新。
大多數人想要改造這個世界,但卻罕有人想改造自己。
世上沒有絕望的處境,只有對處境絕望的人。
————By slience
—————————————————————————————————