演算法1-2:棋盤覆蓋問題
阿新 • • 發佈:2019-01-28
★問題描述:在一個2^k×2^k的方格組成的棋盤中,若恰有一個方格與其他方格不同,則稱該方格為一特殊方格,且稱該棋盤為一特殊棋盤。顯然特殊方格在棋盤上出現的位置有4^k種情形。因而對任何k≥0,有4^k種不同的特殊棋盤。在棋盤覆蓋問題中,要用L型骨牌覆蓋一個給定棋盤上除特殊方格以外的所有方格,且任何2個L型骨牌不得重複覆蓋。
★演算法設計:利用分治策略,可以設計解棋盤演算法問題的一個簡潔演算法。
★資料輸入:輸入一個K值作為棋盤的大小,之後輸入兩個值作為特殊方格的位置
★資料輸出:輸出棋盤,要求標出每個L型骨牌的序號
例:
輸入:
2
2 2
輸出:
2 2 3 3
2 0 1 3
4 1 1 5
4 4 5 5
首先來分析一下,在棋盤裡只有一塊特殊的方格,而且棋盤的大小也比較特殊,2的K次方,非常適合切分成一半。又因為棋盤是個方形的,所以思路可以使將棋盤分成大小相同的四份。
分支法的基本思想是一個較大的問題,將其分成n個子問題,並且n個子問題解決後能合併成原問題的解。
當我們將有特殊方格的棋盤分割成4個相同的子棋盤時,4個棋盤分成兩類:有特殊方格和沒有特殊方格。我們用到的L型骨牌剛好是三個方格的,也就是說可以用一個L型骨牌將其餘的三個沒有特殊方格的棋盤變成有特殊方格的。
之後我們便可利用遞迴的方法來對其進行賦值。
用一個全域性變數來記錄用骨牌的個數,每層的骨牌序號用一個變數來記錄,程式如下:
#include <stdio.h> #include <stdlib.h> int size;//用於記錄棋盤的大小 int tile=0;//用於記錄骨牌的序號 int a[128][128]={-1}; void ChessBoard(int tr,int tc,int dr,int dc,int size); int main() { int i,j,k; printf("請輸入K值的大小:\n"); scanf("%d",&i); for(j=0,k=1;j<i;j++) k*=2; printf("輸入特殊方格位置:\n"); scanf("%d%d",&i,&j); i--;j--; a[i][j]=0; ChessBoard(0,0,i,j,k); for(i=0;i<k;i++){ for(j=0;j<k;j++) if(a[i][j]>9||a[i][j]==-1) printf(" %d",a[i][j]); else printf(" %d",a[i][j]); printf("\n"); } return 0; } void ChessBoard(int tr,int tc,int dr,int dc,int size){ if(size==1)return; int t=++tile;//t用於儲存在這一層遞迴中骨牌的序號 int s=size/2; if(dr<tr+s&&dc<tc+s) ChessBoard(tr,tc,dr,dc,s); else { a[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 { a[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 { a[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 { a[tr+s][tc+s]=t; ChessBoard(tr+s,tc+s,tr+s,tc+s,s); } }
本文使用的程式碼為C語言的程式碼,在和同學一起討論的過程中,發現C++中呼叫函式的括號可以用中括號,編譯時不會顯示出錯,但是執行時並不會呼叫該函式,希望在以後使用C++編程式碼時可以注意一下,程式碼的執行結果如下: