棋盘覆盖问题 (分治法)

来源:互联网 发布:抗震神器 知乎 编辑:程序博客网 时间:2024/05/22 17:33

棋盘覆盖问题

问题的描述:
¢在一个 2k×2k个方格组成的棋盘中,若恰有一个方格与其他方格不同,称该方格为特殊方格,且称该棋盘为特殊棋盘(Defective Chessboard)。
l特殊方格在棋盘中出现的位置有 4k种情形,就有4k种不同的棋盘。
¢图中的特殊棋盘是当k=2时16个特殊棋盘中一个。在棋盘覆盖问题中,要求用图所示的4种不同形状的L型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且任何两个L型骨牌不得重叠覆盖。在任何一个个 2k×2k的棋盘覆盖中,用到的L型骨牌个数为(4k-1)/3。






问题的分析:
¢用分治策略,可以设计解棋盘覆盖问题的一个简捷算法。分治的技巧在于如何划分棋盘,使划分后的子棋盘大小相同,并且每个子棋盘均包含一个特殊方格,从而将原问题分解为规模较小的棋盘覆盖问题。
l当k>0时,将2k×2k的棋盘划分为4个2k-1×2k-1子棋盘。
l原棋盘只有一个特殊方格,则其余3个子棋盘中没有特殊方格。
l用一个L型骨牌覆盖这3个较小棋盘的会合处。从而将原问题转化为4个较小规模的棋盘覆盖问题,以便采用递归方法求解。
l递归地使用这种划分策略,直至将棋盘分割为1×1的子棋盘。






程序:
#include "iostream"using namespace std;int board[1025][1025];int tile = 1;//tr,tc棋盘左上角方格坐标, dr, dc特殊方格所在坐标, size为行数void ChessBoard(int tr, int tc, int dr, int dc, int size){if(size == 1)return;int t = tile++;// L型骨牌号int 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{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{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{board[tr + s][tc + s] = t;ChessBoard(tr + s, tc + s, tr + s, tc + s, s);}}int main(){int k, x, y, i, j;while(cin>>k){tile = 1;cin>>x>>y;int size = 1<<k;board[x][y] = 0;ChessBoard(0, 0, x, y, size);for(i = 0; i < size; i++){for(j = 0; j < size; j++)cout<<board[i][j]<<"\t";cout<<endl;}}return 0;}