解释2中的问题:
当k>0时,我们把规模为2k * 2k的大棋盘划分为2(k-1) * 2(k-1)的四个小棋盘。
则此时的特殊方格位于四个棋盘其中之一,为了将其余的三个棋盘也同样转化成和原问题相同的棋盘,我们只需要根据划分后特殊棋盘的位置选择合适的骨牌放置在大棋盘的汇合处。如图:
这样就得到了四个和原问题相同的规模更小的子问题,再将子问题进行相同的处理,直到问题规模变为1直接返回。
代码分析
#include
#include
using namespace std;
const int N=1100;
int g[N][N]; //棋盘数组
int title=1; //骨牌编号
void SetColor(int fore = 7, int back = 0)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), (back << 4) + fore);
}//背景颜色
void solve(int tr,int tc,int dr,int dc,int size){
/*tr棋盘左上角行号,tc棋盘左上角列号,size棋盘宽度,dr特殊位置行号,dc特殊位置列号*/
if(size==1) return; //递归出口
int t=title++;
int s=size/2; //分割棋盘
//处理左上角部分
if(dr<tr+s&&dc<tc+s){
solve(tr,tc,dr,dc,s);
}else{
g[tr+s-1][tc+s-1]=t;
solve(tr,tc,tr+s-1,tc+s-1,s);
}
//处理右上角部分
if(dr<tr+s&&dc>=tc+s){
solve(tr,tc+s,dr,dc,s);
}else{
g[tr+s-1][tc+s]=t;
solve(tr,tc+s,tr+s-1,tc+s,s);
}
//处理右下角部分
if(dr>=tr+s&&dc>=tc+s){
solve(tr+s,tc+s,dr,dc,s);
}else{
g[tr+s][tc+s]=t;
solve(tr+s,tc+s,tr+s,tc+s,s);
}
//处理左下角部分
if(dr>=tr+s&&dc<tc+s){
solve(tr+s,tc,dr,dc,s);
}else{
g[tr+s][tc+s-1]=t;
solve(tr+s,tc,tr+s,tc+s-1,s);
}
}
int main(){
int a,b,legth;
cin>>a>>b>>legth;
solve(1,1,a,b,legth);
for(int i=1;i<=legth;i++){
for(int j=1;j<=legth;j++){
if(g[i][j]){
SetColor(0, g[i][j]);
printf("%4d",g[i][j]);
}
else{
printf("%4d",g[i][j]);
}
}
printf("\n");
}
return 0;
}
代码思路:
输入棋盘左上角的坐标(此处为(1,1))和棋盘的宽度,然后借助solve函数进行处理,每次将原棋盘分割为4个小棋盘,然后根据左上、右上、右下、左下的顺时针顺序进行处理,如果特殊方格存在于该小棋盘则直接递归处理该小棋盘。否则,先将该小棋盘的指定位置覆盖上骨牌转换成和原问题相同的问题后在进行分割处理。
实现思路:
借助结构体存储棋盘相关信息(左上角的坐标,特殊方格的位置坐标,棋盘的宽度),先将原棋盘入队列,每次取出队首的元素,当队首元素的规模不为1时,对其进行处理,再将分割后的子棋盘入队,不断循环直至队列为空。
#include
#include
void SetColor(int fore = 7, int back = 0)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), (back << 4) + fore);
}//背景颜色
using namespace std;
const int N=1100;
int g[N][N];
int title=1;
struct Point{
int x;
int y;
int tx;
int ty;
int size;
}p;
queue<Point> q;
int main(){
int a,b,length;
cin>>a>>b>>length;
q.push({1,1,a,b,length});
while(!q.empty()){
Point c=q.front(); //取出队首元素
int tr,tc,dr,dc;
if(c.size!=1){
int s=c.size/2;
int t=title++;
tr=c.x;
tc=c.y;
dr=c.tx;
dc=c.ty;
if(dr<tr+s&&dc<tc+s){
q.push({tr,tc,dr,dc,s});
}else{
g[tr+s-1][tc+s-1]=t;
q.push({tr,tc,tr+s-1,tc+s-1,s});
}
if(dr<tr+s&&dc>=tc+s){
q.push({tr,tc+s,dr,dc,s});
}else{
g[tr+s-1][tc+s]=t;
q.push({tr,tc+s,tr+s-1,tc+s,s});
}
if(dr>=tr+s&&dc>=tc+s){
q.push({tr+s,tc+s,dr,dc,s});
}else{
g[tr+s][tc+s]=t;
q.push({tr+s,tc+s,tr+s,tc+s,s});
}
if(dr>=tr+s&&dc<tc+s){
q.push({tr+s,tc,dr,dc,s});
}else{
g[tr+s][tc+s-1]=t;
q.push({tr+s,tc,tr+s,tc+s-1,s});
}
q.pop();
}else{
//q.pop();
break;
}
}
for(int i=1;i<=length;i++){
for(int j=1;j<=length;j++){
if(g[i][j]){
SetColor(0, g[i][j]);
printf("%4d",g[i][j]);
}
else{
printf("%4d",g[i][j]);
}
}
printf("\n");
}
return 0;
}
注: 在处理时发现,只要此时队首元素的规模为1,则队列中其余元素的规模全为1都无需进行处理,因此当出现队首元素为1时可以直接终止循环,无需等到队列为空。
实现思路:
借助结构体存储棋盘相关信息(左上角的坐标,特殊方格的位置坐标,棋盘的宽度),先将原棋盘入栈,每次取出栈顶的元素,当栈顶元素的规模不为1时,对其进行处理,再将分割后的子棋盘入栈,不断循环直至栈为空。
#include
#include
using namespace std;
const int N=1100;
int g[N][N];
int title=1;
void SetColor(int fore = 7, int back = 0)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), (back << 4) + fore);
}//背景颜色
struct Point{
int x;
int y;
int tx;
int ty;
int size;
}p;
stack<Point> st;
int main(){
int a,b,length;
cin>>a>>b>>length;
st.push({1,1,a,b,length});
while(!st.empty()){
Point c=st.top();
int tr,tc,dr,dc;
if(c.size!=1){
int s=c.size/2;
int t=title++;
tr=c.x;
tc=c.y;
dr=c.tx;
dc=c.ty;
st.pop();
if(dr<tr+s&&dc<tc+s){
st.push({tr,tc,dr,dc,s});
}else{
g[tr+s-1][tc+s-1]=t;
st.push({tr,tc,tr+s-1,tc+s-1,s});
}
if(dr<tr+s&&dc>=tc+s){
st.push({tr,tc+s,dr,dc,s});
}else{
g[tr+s-1][tc+s]=t;
st.push({tr,tc+s,tr+s-1,tc+s,s});
}
if(dr>=tr+s&&dc>=tc+s){
st.push({tr+s,tc+s,dr,dc,s});
}else{
g[tr+s][tc+s]=t;
st.push({tr+s,tc+s,tr+s,tc+s,s});
}
if(dr>=tr+s&&dc<tc+s){
st.push({tr+s,tc,dr,dc,s});
}else{
g[tr+s][tc+s-1]=t;
st.push({tr+s,tc,tr+s,tc+s-1,s});
}
}else{
st.pop();
//break;
}
}
for(int i=1;i<=length;i++){
for(int j=1;j<=length;j++){
if(g[i][j]){
SetColor(0, g[i][j]);
printf("%4d",g[i][j]);
}
else{
printf("%4d",g[i][j]);
}
}
printf("\n");
}
return 0;
}
附加
为了帮助大家清晰的理解棋盘覆盖,三种实现方法的具体步骤,笔者采用python编写了可视化的小工具。
棋盘覆盖工具.