一、实验目的
1.掌握基于递归方法求解分治问题的基本原理。
2.掌握棋盘覆盖问题递归函数的设计方法。
3.掌握基于递归分治方法求解棋盘覆盖问题的具体步骤。
4.具备运用递归分治方法设计算法并解决其他实际应用问题的能力
5. 通过对棋盘覆盖问题的求解,加深对递归和分治思想的理解
二、实验环境
操作系统:Windows10
实验平台:CodeBlocks
编译器:Gcc
实验语言:C++
三、实验内容
用4种不同的L型骨牌覆盖一个给定的特殊棋盘上除去特殊方格外的所有方格,且任何两个L型骨牌不得重复覆盖(在一个2^k*2^k个方格组成的棋盘中,若恰有一个方格与其他方格不同,则称该方格为特殊方格,在程序实现中,用字符0表示特殊方格),如图所示,红色为特殊方格,其次为覆盖所用到的4种不同的L型骨牌。
四、算法描述
分析可知:在2^k*2^k的棋盘覆盖中,用到的L型骨盘数为(4^k-1)/3个,即(所有方格个数-特殊方格个数)/3 ,特殊方格出现的位置有4^k种情况,即k>=0,有4^k种不同的特殊棋盘将2k x 2k的棋盘划分为2(k-1) x 2(k-1)这样的子棋盘4块。
递归填充各个棋子,填充分为四种情况
如果特殊方格在左上子棋盘,则递归填充左上子棋盘;否则填充左上子棋盘的右下角,将右下角看作特殊方格,然后递归填充左上棋盘。
如果特殊方格在右上子棋盘,则递归填充右上子棋盘;否则填充右上子棋盘的左下角,将左下角看作特殊方格,然后递归填充右上棋盘。
如果特殊方格在左下子棋盘,则递归填充左下子棋盘;否则填充左下子棋盘的右上角,将右上角看作特殊方格,然后递归填充左下棋盘。
如果特殊方格在右下子棋盘,则递归填充右下子棋盘;否则填充右下子棋盘的左上角,将左上角看作特殊方格,然后递归填充右下棋盘。
时间复杂度分析:
五、实验结果
输入K=3,即棋盘大小为8*8格,设置特殊方格坐标为(0,1),即棋盘第一行第二个位置,程序运行结果显示可以覆盖(L型骨牌分别用‘!’,‘#’,‘*’的组合进行标识)
输入K=4,即棋盘大小为16*16格,设置特殊方格坐标为(0,1),即棋盘第一行第二个位置,程序运行结果显示可以覆盖(L型骨牌分别用‘!’,‘#’,‘*’的组合进行标识)
六、实验总结
通过棋盘覆盖试验,理解了递归与分治策略算法的思想和递归程序的执行过程,深刻了解到递归对于简化程序编写的重要作用,了解到递归可以使代码更加清晰,可读性更好,减轻了程序编写者的负担。通过实验,增强了编写递归程序和分治算法的能力。
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 16384;
//最多支持k等于14 即2 14次方
int tile = 1;//全局变量 骨牌编号
char Board[maxn][maxn];//棋盘
void ChessBoard(int tr,int tc,int dr,int dc,int size);
int main()
{
int k;
int a, b;
cout << "please input k(the size of chessboard):" << endl;
cin >> k;
cout << "input the specoial point position:" << endl;
cin >> a >> b;
int aSize = pow(2,k);
for(int i=0; i<aSize; i++)
{
for(int j=0; j<aSize; j++)
{
Board[i][j] = '0';
}
}
ChessBoard(0,0,a,b,aSize);
for(int i=0; i<aSize; i++)
{
for(int j=0; j<aSize; j++)
{
printf("%c",Board[i][j]);
}
cout<<endl;
}
}
/**
* tr : 棋盘左上角的行号,tc棋盘左上角的列号
* dr : 特殊方格左上角的行号,dc特殊方格左上角的列号
* size :size = 2^k 棋盘规格为2^k*2^k
*/
void ChessBoard(int tr,int tc,int dr,int dc,int size)
{
if(size == 1)
{
return;
}
int t = tile++;//L型骨牌编号
int s = size/2;//分割棋盘
char signal;
if (t % 3 == 0){
signal = '#';
}else if (t % 3 == 1){
signal = '!';
}else{
signal = '*';
}
//覆盖左上角子棋盘
if(dr<tr+s && dc<tc+s)//特殊方格在此棋盘中
{
ChessBoard(tr,tc,dr,dc,s);
}
else//特殊方格不在此棋盘中
{
//用编号为t的骨牌覆盖右下角
Board[tr+s-1][tc+s-1] = signal;
//覆盖其余方格
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的骨牌覆盖左下角
Board[tr+s-1][tc+s] = signal;
//覆盖其余方格
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的骨牌覆盖右上角
Board[tr+s][tc+s-1] = signal;
//覆盖其余方格
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的骨牌覆盖左上角
Board[tr+s][tc+s] = signal;
//覆盖其余方格
ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}