今天來講講棋盤覆蓋,其實是算法課講到了這一問題,也順便復習一下。
棋盤覆蓋問題其實就是將含有特殊方格且具有一定規格的棋盤用各種L型方格覆蓋,這個問題用分治和遞歸解決起來比較簡單。下面就是一個例子的解決答案。(棋盤的大小為4*4,特殊方格為(1,1))
下面詳細講一下棋盤覆蓋問題的具體細節。此問題的棋盤具有一定的特殊性,為2的n次方(因為只有這樣才可以保證可以完美解決問題)。特殊方格的位置不定,只要在棋盤的內部。在這里除去特殊方格,其他的方格要用不可以間斷的L型方格覆蓋。L型方格的形狀不固定(只要是L型)。上圖還是一個理解的例子。相同數字為一個L型方格。
下面講一下具體的解決思路。遞歸在前面已經講過,不再敘述。這里講一下思路。將棋盤分割成4個子棋盤,將特殊方格所在的子棋盤單獨處理。先講一講其他的三個子棋盤。將其他的三個子棋盤的方位對角的方格標記為特殊方格,在用遞歸繼續求解各個子棋盤的解決答案。如上圖,0為特殊方格,將棋盤分為四個子棋盤。分別為
左上角 右上角
左下角
右下角
將特殊方格不在的其他三個子棋盤的對角方格標記為特殊棋盤。如右上角的子棋盤就是該棋盤的左下角的方格1為特殊方格。這樣就保證棋盤的覆蓋都是L型方格。子棋盤標記好特殊方格后直接遞歸,交給下一步去計算子棋盤的解。特殊方格所在的子棋盤不用標記,直接遞歸。這樣直到當前的棋盤為1時,跳出遞歸,解決問題。因為本人的敘述可能有些問題,要是還不懂的話可以看一下別人對問題的敘述。。。
下面講一講算法的具體實現,因為用到遞歸,所以遞歸的主體和遞歸的邊界比較重要。遞歸主體主要由四個if判斷語句構成,分別代表將棋盤分割的四個子棋盤。if語句要先判斷特殊方格的位置,在將下一步的特殊方格標記。用遞歸交給下一步。這里要注意,因為要與下一步區別開來,但是一個特殊方格的位置參數顯然不夠,這里還要在傳一個當前子棋盤的左上角的方格的坐標,所以就有了四個參數,同時因為棋盤要分割,所以還要傳一個當前棋盤的大小。所以,總共需要五個參數。函數的主體已經解決了,下面說一說遞歸的邊界,因為擔心邊界的問題,所以這里直接將棋盤的大小設置為1時,遞歸結束。(也可以將棋盤的大小遞歸邊界設置為2,但是要考慮一些細節問題,這里不再敘述)好了,算法的遞歸完成,剩下的就是一些細節問題。比如講特殊方格標記。。。這里不再敘述,都在代碼里了。下面就是代碼。
import java.util.Scanner; public class demo { static int title=1; static int a[][]=new int[100][100]; //tr,tc分別為當前棋盤的行號和列號。dr,dc為特殊方格的行號和列號。size為棋盤的大小。 public static void qipanfugai(int tr,int tc,int dr,int dc,int size) { //遞歸邊界 if(size==1)//這里的size為上一層的s,當s為2時還要遞歸一次。再遞歸一次的時候t會被在加一次 { return; } int t=title++;//覆蓋棋盤的數字 //System.out.println(t+"t被加了一次"); int s=size/2;//s為將棋盤分割 //遞歸主體 //左上角棋盤覆蓋 if(dr<tr+s&&dc<tc+s){//特殊方格在左上角,下面也是一樣 qipanfugai(tr, tc, dr, dc, s); //System.out.println("哈哈"); }else{ a[tr+s-1][tc+s-1]=t;//用t覆蓋右下角的方格 qipanfugai(tr, tc, tr+s-1, tc+s-1, s);//遞歸給下一步,特殊方格的位置發生了變化 } //右上角棋盤覆蓋 if(dr<tr+s&&dc>=tc+s){ qipanfugai(tr, tc+s, dr, dc, s); }else{ a[tr+s-1][tc+s]=t; qipanfugai(tr, tc+s, tr+s-1, tc+s, s); } //左下角棋盤覆蓋 if(dr>=tr+s&&dc<tc+s){ qipanfugai(tr+s, tc, dr, dc, s); }else{ a[tr+s][tc+s-1]=t; qipanfugai(tr+s, tc, tr+s, tc+s-1, s); } //右下角棋盤覆蓋 if(dr>=tr+s&&dc>=tc+s){ qipanfugai(tr+s, tc+s, dr, dc, s); }else{ a[tr+s][tc+s]=t; qipanfugai(tr+s, tc+s, tr+s, tc+s, s); } } public static void main(String args[]) { System.out.println("請輸入棋盤的大小和特殊方格的位置。輸入格式為“4 2 2”"); Scanner reader = new Scanner(System.in); int dr,dc,size; size=reader.nextInt(); dr=reader.nextInt(); dc=reader.nextInt(); System.out.println(); qipanfugai(0,0, dr, dc, size);//特殊方格沒有動,所以一直為0 for(int i=0;i<size;i++) { for(int j=0;j<size;j++) { System.out.print(a[i][j]+" "); } System.out.println(); } } }
算法總體還是比較好理解的,都是一些細節的問題。我在一些細節問題上面卡了好久,比如要先判斷棋盤的大小是否為1,在去執行下一步,要不然就會出現下面的情況。
答案也對,但是感覺怪怪的。剩下的一些問題都寫在注釋里了。就這樣吧