參考blog
問題描述
在一個(gè)2^k * 2^k個(gè)方格組成的棋盤中,有一個(gè)方格與其它的不同,若使用以下四種L型骨牌覆蓋除這個(gè)特殊方格的其它方格,如何覆蓋。四個(gè)L型骨牌如下圖:
棋盤中的特殊方格如圖:
????????實(shí)現(xiàn)的基本原理是將 2k x 2k 的棋盤分成四塊 2(k-1) x 2(k-1)的子棋盤,特殊方格一定在其中的一個(gè)子棋盤中,如果特殊方格在某一個(gè)子棋盤中,繼續(xù)遞歸處理這個(gè)子棋盤,直到這個(gè)子棋盤中只有一個(gè)方格為止如果特殊方格不在某一個(gè)子棋盤中,將這個(gè)子棋盤中的相應(yīng)的位置設(shè)為骨牌號(hào),將這個(gè)無特殊方格的了棋盤轉(zhuǎn)換為有特殊方格的子棋盤,然后再遞歸處理這個(gè)子棋盤。以上原理如圖所示:
棋盤覆蓋程序如下:
//2d6 棋盤覆蓋問題
#include "stdafx.h"
#include <iostream>
using namespace std;
int tile = 1;//全局變量 骨牌編號(hào)
int Board[4][4];//棋盤
void ChessBoard(int tr,int tc,int dr,int dc,int size);
int main()
{
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
{
Board[i][j] = 0;
}
}
ChessBoard(0,0,2,3,4);
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
{
cout<<Board[i][j]<<" ";
}
cout<<endl;
}
}
/**
* tr : 棋盤左上角的行號(hào),tc棋盤左上角的列號(hào)
* dr : 特殊方格左上角的行號(hào),dc特殊方格左上角的列號(hào)
* size :size = 2^k 棋盤規(guī)格為2^k*2^k
*/
void ChessBoard(int tr,int tc,int dr,int dc,int size)
{
if(size == 1)
{
return;
}
int t = tile++;//L型骨牌編號(hào)
int s = size/2;//分割棋盤
//覆蓋左上角子棋盤
if(dr<tr+s && dc<tc+s)//特殊方格在此棋盤中
{
ChessBoard(tr,tc,dr,dc,s);
}
else//特殊方格不在此棋盤中
{
//用編號(hào)為t的骨牌覆蓋右下角
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//特殊方格不在此棋盤中
{
//用編號(hào)為t的骨牌覆蓋左下角
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//特殊方格不在此棋盤中
{
//用編號(hào)為t的骨牌覆蓋右上角
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//特殊方格不在此棋盤中
{
//用編號(hào)為t的骨牌覆蓋左上角
Board[tr+s][tc+s] = t;
//覆蓋其余方格
ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}
程序運(yùn)行結(jié)果如下:
思考
第一步(尋求最小的求解) :
2x2
當(dāng)只有2x2時(shí),剛好一個(gè)L型骨牌 + 特殊方格(任意4個(gè)角都可) 。可是暫時(shí)看不到如何擴(kuò)張,所以得考慮4x4的模型。
4x4
1.可以分割成4 個(gè) 2x2,分別為左上角,右上角,左下角和右下角。
2.右上角可以直接用2x2情況求解,可是其他3塊2x2右得按什么 有序步驟 求解?
既然是分治法必然會(huì)用到遞歸,那么大問題必然分解為N個(gè)重復(fù)可解的小問題(當(dāng)然小問題的類型個(gè)數(shù)要可控,一般為1到4個(gè))
數(shù)學(xué)模型:
g(x) = af1(x) + bf2(x) + cf3(x) + df4(x), 其中fi(x)為可解的小問題,a,b,c,d為小問題重復(fù)的次數(shù)
根據(jù)公式,我們可以
1.先找各f(x)
2.將f(x)相加成g(x)
1.現(xiàn)階段我們已經(jīng)分解為2個(gè)小問題:
f1(x) :存在特殊方格的2x2棋盤的求解
f2(x) : 3個(gè)沒有特殊方格的2x2棋盤的求解
- 當(dāng)然f1(x)已經(jīng)解決,接著考慮f2(x)。
2.1 考慮f1(x)在4x4的左上角
如圖是f2(x)求解,
f2(x)解步驟 :1.每個(gè)2x2先放一個(gè)L型骨牌(缺口朝向中央,也只能這樣放),2.在中央放一塊L型骨牌(缺口朝向存在特殊方格的2x2棋盤)
2.2 考慮f1(x)在4x4的其他角落塊,同2.1。
第一步 結(jié)尾
那么此時(shí)我們已經(jīng)找到了f(x)并都得到了有序解步驟:
f1(x) :存在特殊方格的2x2棋盤的求解
f2(x) : 3個(gè)沒有特殊方格的2x2棋盤的求解
第二步(組合f(x)來求解g(x)) :
我們將f(x)來接下 8x8時(shí)的情況:
分解成4塊4x4,存在特殊方格的4x4棋盤同第一步分析求解,可是其他3塊4x4不能分解成f2(x) ,所以現(xiàn)在的f1(x) 和f2(x)不滿足,從新第一步,求f(x)
重復(fù)第一步 :
觀察現(xiàn)有的f1(x) 和f2(x)
f1(x) 無法更改
f2(x) 可考慮。同時(shí)在8x8中也是f2(x)不滿足,那么我們得出一套滿足各2k x 2k有序解步驟
其實(shí)有2個(gè)解決口:
1.將f2(x)步驟顛倒試試
2.在2k x 2k中分解的每個(gè)2(k-1) x 2(k-1)棋盤必然應(yīng)該是相同操作的,那么得出每個(gè)2x2棋盤也應(yīng)該是同f1(x),那么就是給沒有特殊方格的2x2棋盤各個(gè)一個(gè)特殊方塊(同時(shí)3個(gè)特殊方塊也可以組成一個(gè)L型骨牌)
新的f(x)
f1(x) :存在特殊方格的2x2棋盤的求解
f2(x) : 3個(gè)沒有特殊方格的2x2棋盤各給一個(gè)特殊方塊(同時(shí)3個(gè)特殊方塊也可以組成一個(gè)L型骨牌),變成f1(x)的求解
f2(x) =f3(x) + 3 *f1(x)
f3(x) : 3個(gè)沒有特殊方格的2x2棋盤各給一個(gè)特殊方塊(同時(shí)3個(gè)特殊方塊也可以組成一個(gè)L型骨牌)
進(jìn)入第二步
進(jìn)行歸納法
先證明4x4依據(jù)2x2可解,再證明2k x 2k 的棋盤依據(jù) 2(k-1) x 2(k-1)的棋盤可解得出f(x)滿足需求
那么遞歸項(xiàng)就是
f1(x) +f2(x) = f1(x) +f3(x) + 3 *f1(x) = f3(x) + 4 * f1(x)
在f1(x) 合并時(shí),要將 f3(x) 提前,因?yàn)橛? *f1(x) 在 f3(x) 后
接下來就可以根據(jù)有序的解步驟寫程序了