分治策略之棋盤覆蓋問題(ChessBoard)
阿新 • • 發佈:2019-01-31
在一個2k×2k個方格組成的棋盤中,恰有一個方格與其它方格不同,稱該方格為一特殊方格,且稱該棋盤為一特殊棋盤。在棋盤覆蓋問題中,要用圖示的4種不同形態的L型骨牌覆蓋給定的特殊棋盤上除特殊方格以外的所有方格,且任何2個L型骨牌不得重疊覆蓋。
當k>0時,將2k×2k棋盤分割為4個2k-1×2k-1子棋盤(a)所示。
特殊方格必位於4個較小子棋盤之一中,其餘3個子棋盤中無特殊方格。為了將這3個無特殊方格的子棋盤轉化為特殊棋盤,可以用一個L型骨牌覆蓋這3個較小棋盤的會合處,如(b)所示,從而將原問題轉化為4個較小規模的棋盤覆蓋問題。遞迴地使用這種分割,直至棋盤簡化為棋盤1×1。
將棋盤儲存在一個二維陣列中。骨牌號從1開始,特殊方格為0,如果是一個4 * 4的棋盤,特殊方格為(2,2),那麼程式的輸出為
2 2 3 3
2 1 1 3
4 1 0 5
4 4 5 5
相同數字的為同一骨牌。
//棋盤覆蓋(遞迴) #include <iostream> #include<iomanip> using namespace std; /** tr:棋盤左上角方格的行號; tc:棋盤左上角方格的列號; dr:特殊方格所在的行號; dc:特殊方格所在的列號; title:全域性整型變數; Board[N][N]:棋盤方格;N為2的倍數; */ static int title = 1; const int N = 8; int Board[N][N] = {0}; void ChessBoard(int tr, int tc, int dr, int dc, int size) { if(size == 1) return; int t = 0,s = 0; t = title++; //L型骨牌號 s = size/2; //分割棋盤 //覆蓋左上角子棋盤 if(dr < tr+s && dc < tc+s ) { //特殊方格在此棋盤中 ChessBoard(tr,tc,dr,dc,s); } else { //此棋盤中無特殊方格 //用t號L型骨牌覆蓋右下角 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 { //此棋盤中無特殊方格 //用t號L型骨牌覆蓋左下角 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 { //此棋盤中無特殊方格 //用t號L型骨牌覆蓋左下角 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 { //此棋盤中無特殊方格 //用t號L型骨牌覆蓋左下角 Board[tr+s][tc+s] = t; //覆蓋其餘方格 ChessBoard(tr+s,tc+s,tr+s,tc+s,s); } } int main() { cout<<"請輸入特殊盤的下標號:"<<endl; int x,y; cout<<"行: "; cin>>x; cout<<"列: "; cin>>y; cout<<endl; ChessBoard(0,0,x,y,N); cout<<endl; for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) { cout<<setw(4)<<Board[i][j]; } if(0 == i/N) cout<<endl; } return 0; }