一、引子
最近又重新上了算法課,現在想來有點汗顏,大學期間已經學習了一個學期,到現在卻依然感覺只是把老師講過的題目弄懂了,並沒有學到算法的一些好的分析方法和思路,碰到一個新的問題後往往感覺很棘手,痛定思痛之後覺得還是好好再學習一遍,爭取能理解透徹每種算法的思路和核心,同時也勸誡各位同行們做事要腳踏實地,不能應付老師的作業,最後喫虧的還是自己啊。
二、棋盤覆蓋問題
爲一特殊棋盤。現有四種L型骨牌如下圖所示,要用這四種骨牌覆蓋棋盤上除特殊方格之外的其他所有格子,且兩個L型骨牌不能相互覆蓋。
三、解題思路
假設特殊格子出現在(0,2)這個位置,如圖3所示,那麼對於含有特殊格子的右上角的子棋盤我們用0型骨牌填充,如圖4。那麼剩餘的三個子棋盤呢,這個時候我們發現左上角只能覆蓋3型和2型,其他兩種會有剩餘空格,如果覆蓋2型骨牌,後面的左下角必然無法完全覆蓋(自己可以試一下),則只能使用3型骨牌覆蓋,以此類推,我們也可以覆蓋左下角和右下角此時只剩三個格子沒有覆蓋,如圖5所示。現在仔細觀測剩餘的三個格子,我們發現他們都是分開在三個子棋盤裏,那麼這些空格子在子棋盤中是無法直接被覆蓋的,因爲每個子棋盤只剩一個空格子了,我們是不是可以把這個空格子當成一個特殊格子,這樣四個子棋盤都是含有一個特殊格子的小棋盤,這樣原問題就變成了四個同樣的子問題,再求解了每個子棋盤後,我們再對三個假的子棋盤格子進行覆蓋(如圖6)。
那麼如何選擇空格作爲子棋盤的特殊格子呢,通過觀察我們發現,對於含有特殊格子的子棋我們不用指定特殊格子,對於剩下三個子棋盤,我們指定四個子棋盤的交界處的格子作爲特殊格子。
四、歸納
五、代碼實現
#include <iostream>
#include<memory.h>
using namespace std;
int **chessBoard;
int k=1;
int length=0;
int blueRow=-1;
int blueCol=-1;
void init();
void fillBoard(int **_chessBoard,int r,int c,int type);
void fillChessBoard(int **_chessBoard,int k,int blue_row,int blue_col,int baseRow,int baseCol);
void output(int **_chessBoard);
int main()
{
init();
fillChessBoard(chessBoard,k,blueRow,blueCol,0,0);
output(chessBoard);
for(int i=0;i<length;i++)
{
delete [] chessBoard[i];
}
delete chessBoard;
return 0;
}
void init()
{
cout<<"please input number k:"<<endl;
cin>>k;
cout<<"please input blue grid coordinate:row column"<<endl;
cin>>blueRow>>blueCol;
length=(1<<k);//長和寬均爲2^k
//動態分配2^k數組
chessBoard=new int*[length];
for(int i=0;i<length;i++)
{
chessBoard[i]=new int[length];
//初始化爲-1
memset(chessBoard[i],-1,length*sizeof(int));
}
chessBoard[blueRow][blueCol]=4;
}
void output(int **_chessBoard)
{
for(int i=0;i<length;i++)
{
for(int j=0;j<length;j++)
{
cout<<" "<<_chessBoard[i][j];
}
cout<<endl;
}
cout<<endl;
}
void fillBoard(int **_chessBoard,int r,int c,int type)
{
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
if((i*2+j)!=type)
{
if(_chessBoard[r+i][c+j]!=-1)
cout<<"error"<<endl;
_chessBoard[r+i][c+j]=type;
}
}
}
}
void fillChessBoard(int **_chessBoard,int level,int blue_row,int blue_col,int baseRow,int baseCol)
{
if(level==1)
{
int type=(blue_row<<1)+blue_col;
fillBoard (_chessBoard,baseRow,baseCol,type);
}else
{
//否則進行四等分,中間連接處自行填充
//新的四分格的寬度
int new_length=1<<(level-1);
int type=(blue_row/new_length)*2+blue_col/new_length;
for(int r=0;r<2;r++)
{
for(int c=0;c<2;c++)
{
if((r*2+c)==type)
{
fillChessBoard (_chessBoard,level-1,blue_row-r*new_length,blue_col-c*new_length,r*new_length+baseRow,c*new_length+baseCol);
}
else
{
fillChessBoard (_chessBoard,level-1,(new_length-1)*(1-r),(new_length-1)*(1-c),r*new_length+baseRow,c*new_length+baseCol);
}
}
}
fillBoard (_chessBoard,baseRow+new_length-1,baseCol+new_length-1,type);
}
}