一、棋盘覆盖问题
1、问题
2、分析
(1)当k>0时,将2k×2k棋盘分割为4个(2k-1)×(2k-1)子棋盘,如图(a)所示。每一次分解,都将原本大小的棋盘,划分为四份,即行号和列号各自缩减一半。
(2)特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊方格。
(3)为将无特殊方格子棋盘转化为特殊棋盘,可以用一个骨牌覆盖3个较小棋盘的会合处,如图(b)所示,从而将原问题转化为4个较小规模的棋盘覆盖问题。即:将骨牌的三个部分分别仿作特殊方格子
(4)递归地使用这种分割,直至棋盘简化为棋盘1×1
3、代码分析
(1)入口参数
tr,tc表示当前棋盘的左上角的坐标(tr,tc)
dr,dc表示特殊方格的坐标(dr,dc)
(2)判断特殊方块在相对于当前棋盘的中心(tr+s,tr+s)哪个位置:
如果在左上,即有(dr<tr+s,dc<tc+s),若不在,则将(tr+s-1,tc+s-1)涂黑
如果在左下,即有(dr≥tr+s,dc<tc+s),若不在,则将(tr+s,tc+s-1)涂黑
如果在右上,即有(dr<tr+s,dc≥tc+s),若不在,则将(tr+s-1,tc+s)涂黑
如果在右上,即有(dr≥tr+s,dc≥tc+s),若不在,则将(tr+s,tc+s)涂黑
如果在,则传入对应特殊方格位置,并缩小规模
4、代码实现
/*棋盘覆盖问题(分治算法)*/ #include<iostream> #include<algorithm> using namespace std; //L型骨牌的编号(递增) int title=65; //棋盘 int Board[10][10]; /*函数形参说明: tr:当前棋盘左上角的行号 tc:当前棋盘左上角的列号 dr:当前特殊方格所在的行号 dc:当前特殊方格所在的列号*/ void ChessBoard(int tr,int tc,int dr,int dc,int size) { if(size == 1) return; /*编号加1,且每执行1次,即将原本的棋盘划分成原来的1/4*/ int t=title++; int s=size/2; /*判断特殊方块的位置*/ //左上 if(dr<tr+s && dc<tc+s) ChessBoard(tr,tc,dr,dc,s); else { 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 size=8; int index_x=3; int index_y=4; ChessBoard(0,0,index_x-1,index_y-1,size); for(int i=0;i<size;i++){ for(int j=0;j<size;j++) cout << (char)Board[i][j] << ' '; cout << endl; } system("pause"); return 1; }
二、循环日程问题
1、问题
设有n=2k个选手要进行网球循环赛,设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其他n-1个选手各赛一次
(2)每个选手一天只能比赛一次
(3)循环赛在n-1天结束
2、分析
规律:(1)左上 = 右下 左下 = 右上
(2)左下的值 = 左上的值 + oldN (n0 = 2,n = oldNnum)
3、代码分析
按照左下、右上、右下的遍历次序进行遍历oldN=n,n=oldN*2
(1)左下,行号遍历范围为[oldN+1,n],列号遍历范围为[1,oldN]
(2)右上,行号遍历范围为[1,oldN],列号遍历范围为[oldN+1,n]
(3)右下,行号遍历范围为[oldN+1,n],列号遍历范围为[oldN+1,n]
4、代码实现
/*循环日程问题(分治算法)*/ #include<iostream> #include<algorithm> using namespace std; int a[1000][1000]; /* (i,j) (i,j+oldN) (i,j+2oldN) (i+oldN,j) (i+oldN,j) (i+2oldN,j+2oldN)*/ void Plan(int k) { int i,j,oldN,n; int num=1; /*原始规模为2,每次规模行和列均‘*2’*/ n=2; a[1][1]=1; a[1][2]=2; a[2][1]=2; a[2][2]=1; /*迭代处理‘2^k’中情况*/ while(num<k) { oldN=n; //右区间的边界 n=n*2; //左下角 for(i=oldN+1;i<=n;i++) for(j=1;j<=oldN;j++) a[i][j]=a[i-oldN][j]+oldN; //右上角(与左下角一致) for(i=1;i<=oldN;i++) for(j=oldN+1;j<=n;j++) a[i][j]=a[i+oldN][j-oldN]; //右下角(与左上角一致) for(i=oldN+1;i<=n;i++) for(j=oldN+1;j<=n;j++) a[i][j]=a[i-oldN][j-oldN]; num++; } } int main() { int k=3; Plan(k); int num=1; for(int i=1;i<=k;i++) num *= 2; for(int i=1;i<=num;i++) { for(int j=1;j<=num;j++) { cout << a[i][j] << "\t"; } cout << endl; } system("pause"); return 1; }标签:int,分治,tr,C语言,算法,棋盘,dr,tc,oldN From: https://www.cnblogs.com/Auion-idiot/p/17811005.html