算法系列之分治算法(棋盤問題)

分治算法(官方解釋):

當我們求解某些問題時,由於這些問題要處理的數據相當多,或求解過程相當複雜,使得直接求解法在時間上相當長,或者根本無法直接求出。對於這類問題,我們往往先把它分解成幾個子問題,找到求出這幾個子問題的解法後,再找到合適的方法,把它們組合成求整個問題的解法。如果這些子問題還較大,難以解決,可以再把它們分成幾個更小的子問題,以此類推,直至可以直接求出解爲止。這就是分治策略的基本思想。

分治算法(自我理解)

其實就是講很大的計算數據一步步分解到最小,過程中當然少不了我們之前學到的遞歸算法,還借鑑到二分法的算法思想,通過遞歸,將一個大問題分解成兩個小問題,再將兩個小問題分解成四個更小的問題,直到分解到很簡單就能解決的問題,進而依次返回,求出最原始的大問題的解。

棋盤問題:

在一個2^k×2^k (k≥0)個方格組成的棋盤中,恰有一個方格與其他方格不同,稱該方格爲特殊方格。顯然,特殊方格在棋盤中可能出現的位置有4^k種,因而有4^k種不同的棋盤,圖4.10(a)所示是k=2時16種棋盤中的一個。棋盤覆蓋問題(chess cover problem)要求用圖4.10(b)所示的4種不同形狀的L型骨牌覆蓋給定棋盤上除特殊方格以外的所有方格,且任何2個L型骨牌不得重疊覆蓋。

思路:

這個題的思路直到想到這一點我們就很快能編程出來,但是如果想不到,就很難了~

我們把2^k×2^k的方格逐漸分解,(以8*8爲例)講解一下,初始棋盤是8*8的,我們將長和寬都一分爲2,這樣就將棋盤分割成四個部分了,也就是每個都是4*4的棋盤,之後再將每個4*4的棋盤分解成4個2*2的棋盤,再將2*2的棋盤分解成4個1*1的方格了,然後逐步返回,當然,題目中說到有一個特殊的方格,這就需要寫一個遞歸函數去尋找這個特殊方格,既然每個遞歸的過程都把原來的棋盤分解成4個小棋盤,那麼就分別對左上、左下、右上、右下的棋盤進行判斷是否有特殊方格,如果有,就將該部分繼續遞歸分解,直到找到這個特殊方格的位置。

如果特殊方格沒在這個範圍內,就將這個範圍靠近員棋盤中心的那個方格設定爲特殊方格(見圖b),這樣也就有了特殊方格,我們也知道他的位置,就可以通過遞歸進行調用它,知道分解到最小單位的棋盤。

源代碼:

package 分治算法;

public class 棋盤覆蓋 {
public static int tile = 1;//表示L形骨牌的編號
public int [][]board=new int[4][4];//表示4*4的棋盤
//處理帶有特殊棋子的棋盤,tr、tc表示棋盤的入口即左上角的序列數,dr、dc代表特殊棋子的
//位置(序列號),size代表棋盤的行列數
public void chessboard(int tr,int tc,int dr,int dc,int size){
if(size==1)return;
int t=tile++;
System.out.println(t);
int s = size/2;//每次劃大棋盤爲一半的子棋盤
//要處理帶有特殊旗子的棋盤,需要先處理左上角的棋盤
if(dr
chessboard(tr,tc,dr,dc,s);//處理有特殊棋子的左上角棋盤
}else{ //處理無特殊棋子的左上角子棋盤
board[tr+s-1][tc+s-1] = t; //設左上角棋盤的右下角爲特殊棋子用t形的骨牌覆蓋
//由於骨牌骨牌有三種,當處理過程中同一級設置的特殊棋子用相同的骨牌覆蓋
chessboard(tr,tc,tr+s-1,tc+s-1,s);
}

//第二步處理右上角棋盤
if(dr=tc+s){//右上角棋盤有特殊棋子
chessboard(tr,tc+s,dr,dc,s);//處理有特殊棋子的右上角棋盤
}
else{ //處理無特殊棋子的右上角棋盤
board[tr+s-1][tr+s]=t;//設右上角棋盤的左下角爲特殊棋子,用t形的骨牌覆蓋
//由於骨牌有三種,當處理過程中同一級設置的特殊棋子用相同的骨牌覆蓋
chessboard(tr,tc+s,tr+s-1,tc+s,s);
}

//第三種處理左下角的棋盤
if(dr>=tr+s&&dc
chessboard(tr+s,tc,dr,dc,s);//處理有特殊棋子的左下角子棋盤
}
else{//處理沒有左下角的子棋盤
board[tr+s][tc+s-1]=t;//設左下角的右上角爲特殊棋子,用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;//設右下角的左上角爲特殊棋子,用t形的骨牌覆蓋
//由於骨牌有三種,當處理過程中同一級設置的特殊棋子用相同的骨牌覆蓋
chessboard(tr+s,tc+s,tr+s,tc+s,s);
}
}
public static void main(String[] args) {
棋盤覆蓋 c=new 棋盤覆蓋();
c.chessboard(0, 0, 1, 1, 4);
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
System.out.print(c.board[i][j]+" ");
}
System.out.println("");
}
}

}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章