例题 2.6 棋盘覆盖

这是一道涉及递归与分治策略的趣味数学题目,主要探讨如何巧妙地处理棋盘覆盖。通过详细分析各个位置的下标关系,并将棋盘分为四个部分,当特殊点不在特定部分时,将中央三个方块标记为特殊点。文章中配有图表辅助理解,并提供了递归实现的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一道很有趣的递归与分治的题目。

关键搞好各个位置的下标关系,以及将整个图分为四部分,如果特殊点不在此部分,则将整个图中间的三个方块标记为特殊点。注释很详细。


 画了一张图(主要是还得交作业,不然才不画呢,哈哈哈哈):



先贴上递归实现的代码:

/*
棋盘覆盖的递归算法
 棋盘大小为size(2^k)*size大小
*/ 
  
#include<iostream>
const int Max=16;

int map[Max][Max]; 
using namespace std;

int tile;


void ChessBoard(int lr,int lc,int dr,int dc,int size)
{
	if(size==1)return;
	//L型骨牌号 
	int cnt=++tile;
	
	 
	int s=size/2;
	
	//处理左上角部分 
	if(dr<lr+s&&dc<lc+s)//如果特殊方格在左上角 
	{
		ChessBoard(lr,lc,dr,dc,s);
	}
	else  //骨牌覆盖到右下角 
	{
		map[lr+s-1][lc+s-1]=cnt; 
		ChessBoard(lr,lc,lr+s-1,lc+s-1,s); 
	}
	
	//处理右上角部分
	if(dr<lr+s&&dc>=lc+s)
	{
		ChessBoard(lr,lc+s,dr,dc,s);
	}
	else//覆盖到左下角 
	{
		map[lr+s-1][lc+s]=cnt;
		ChessBoard(lr,lc+s,lr+s-1,lc+s,s); 
	 } 
	 
	 //处理左下角部分
	 if(dr>=lr+s&&dc<lc+s)
	 {
	 	ChessBoard(lr+s,lc,dr,dc,s);
	  } 
	  else//覆盖到右上角 
	  {
	  	map[lr+s][lc+s-1]=cnt;
		ChessBoard(lr+s,lc,lr+s,lc+s-1,s); 
	  }
	  
	  //处理右下角部分
	  if(dr>=lr+s&&dc>=lc+s)
	  {
	  	ChessBoard(lr+s,lc+s,dr,dc,s);
	   } 
	   else//覆盖到左上角 
	   {
	   	map[lr+s][lc+s]=cnt;
	   	ChessBoard(lr+s,lc+s,lr+s,lc+s,s);
	   }
}

void display()
{
	for(int i=0;i<Max;i++)
	{
		for(int j=0;j<Max;j++)
		{
		//	cout<<map[i][j]<<" ";
			printf("%-2d ",map[i][j]);
		}
		cout<<endl;
	}
}
int main()
{
	ChessBoard(0,0,0,0,Max);
	display();
	
	return 0;
 } 


栈   模拟实现:敲得晕晕的.........还是递归写起来舒服优美....

#include<iostream>
#include<stack>

using namespace std;
const int Max=8;

int map[Max][Max];

int cnt=1;

struct node{
	int sx,sy;	//每一小块的起始坐标 
	int dx,dy;	//特殊方格的坐标 
	int size;	//小块的大小初始size=2^k; 
	int num;	//用于标记骨牌号 
};

stack<node> s;

void init()
{
	node p;
	p.dx=p.dy=p.sx=p.sy=0;
	p.size=Max;
	p.num=cnt++;
	p.size=Max;
	
	s.push(p);
}


void solve()
{
	while(!s.empty())
	{
		node tmp=s.top();
		s.pop();
		
		//如果每一部分只有一块 
		if(tmp.size==1)
		{
			cnt--;
			continue;
		}
		
		//被分割后的块大小 
		int sz=tmp.size/2; 
		
		//下一个入栈结点值得初始化 
		node next=tmp;
		next.size=tmp.size/2;
		next.num=cnt++;
		
		//处理左上角部分 
		if(tmp.dx<tmp.sx+sz&&tmp.dy<tmp.sy+sz)
		{
			next.sx=tmp.sx;
			next.sy=tmp.sy;
			
			next.dx=tmp.dx;
			next.dy=tmp.dy;
			s.push(next);
		}
		else
		{
			map[tmp.sx+sz-1][tmp.sy+sz-1]=tmp.num;
		//	map[tmp.sy+sz-1][tmp.sx+sz-1]=tmp.num;
			next.dx=tmp.sx+sz-1;
			next.dy=tmp.sy+sz-1;
			
			s.push(next);
		}
		
		next.num=cnt++;
		
		//处理右上角部分 
		if(tmp.dx<tmp.sx+sz&&tmp.dy>=tmp.sy+sz)
		{
			next.sx=tmp.sx;
			next.sy=tmp.sy+sz;
			
			next.dx=tmp.dx;
			next.dy=tmp.dy;
			
			s.push(next);
		}
		else
		{
			map[tmp.sx+sz-1][tmp.sy+sz]=tmp.num;
		//	map[tmp.sy+sz][tmp.sx+sz-1]=tmp.num;
			next.dx=tmp.sx+sz-1;
			next.dy=tmp.sy+sz;
			
			next.sx=tmp.sx;
			next.sy=tmp.sy+sz;
			s.push(next);
		}
		next.num=cnt++;
		
		//处理左下角的部分
		
		if(tmp.dx>=tmp.sx+sz&&tmp.dy<tmp.sy+sz)
		{
			next.sx=tmp.sx+sz;
			next.sy=tmp.sy;
			
			next.dx=tmp.dx;
			next.dy=tmp.dy;
			s.push(next);
		 } 
		 else
		 {
		 	map[tmp.sx+sz][tmp.sy+sz-1]=tmp.num;
		 //	map[tmp.sy+sz-1][tmp.sx+sz]=tmp.num;
		 	next.sx=tmp.sx+sz;
		 	next.sy=tmp.sy;
		 	
		 	next.dx=tmp.sx+sz;
		 	next.dy=tmp.sy+sz-1;
		 	s.push(next);
		 }
		 next.num=cnt++;
		 
		 //处理右下角
		 if(tmp.dx>=tmp.sx+sz&&tmp.dy>=tmp.sy+sz)
		 {
			next.sx=tmp.sx+sz;
			next.sy=tmp.sy+sz;
			
			next.dx=tmp.sx;
			next.dy=tmp.sy;
			s.push(next); 	
		} 
		else
		{
			map[tmp.sx+sz][tmp.sy+sz]=tmp.num;
		//	map[tmp.sy+sz][tmp.sx+sz]=tmp.num;
			next.sx=tmp.sx+sz;
			next.sy=tmp.sy+sz;
			
			next.dx=tmp.sx+sz;
			next.dy=tmp.sy+sz;
			s.push(next); 
		}
		  
		
		
	}

	
}

void display()
{
	for(int i=0;i<Max;i++)
	{
		for(int j=0;j<Max;j++)
		{
			printf("%-3d ",map[i][j]);
		}
		cout<<endl;
	}
}
int main()
{
	init();
	solve();
	display();	
	
	return 0;
}

队列实现:和栈实现相比改了一行代码......

#include<iostream>
#include<queue>

using namespace std;
const int Max=8;

int map[Max][Max];

int cnt=1;

struct node{
	int sx,sy;	//每一小块的起始坐标 
	int dx,dy;	//特殊方格的坐标 
	int size;	//小块的大小初始size=2^k; 
	int num;	//用于标记骨牌号 
};

queue<node> s;

void init()
{
	node p;
	p.dx=p.dy=p.sx=p.sy=0;
	p.size=Max;
	p.num=cnt++;
	p.size=Max;
	
	s.push(p);
}


void solve()
{
	while(!s.empty())
	{
		node tmp=s.front();
		s.pop();
		
		//如果每一部分只有一块 
		if(tmp.size==1)
		{
			cnt--;
			continue;
		}
		
		//被分割后的块大小 
		int sz=tmp.size/2; 
		
		//下一个入栈结点值得初始化 
		node next=tmp;
		next.size=tmp.size/2;
		next.num=cnt++;
		
		//处理左上角部分 
		if(tmp.dx<tmp.sx+sz&&tmp.dy<tmp.sy+sz)
		{
			next.sx=tmp.sx;
			next.sy=tmp.sy;
			
			next.dx=tmp.dx;
			next.dy=tmp.dy;
			s.push(next);
		}
		else
		{
			map[tmp.sx+sz-1][tmp.sy+sz-1]=tmp.num;
		//	map[tmp.sy+sz-1][tmp.sx+sz-1]=tmp.num;
			next.dx=tmp.sx+sz-1;
			next.dy=tmp.sy+sz-1;
			
			s.push(next);
		}
		
		next.num=cnt++;
		
		//处理右上角部分 
		if(tmp.dx<tmp.sx+sz&&tmp.dy>=tmp.sy+sz)
		{
			next.sx=tmp.sx;
			next.sy=tmp.sy+sz;
			
			next.dx=tmp.dx;
			next.dy=tmp.dy;
			
			s.push(next);
		}
		else
		{
			map[tmp.sx+sz-1][tmp.sy+sz]=tmp.num;
		//	map[tmp.sy+sz][tmp.sx+sz-1]=tmp.num;
			next.dx=tmp.sx+sz-1;
			next.dy=tmp.sy+sz;
			
			next.sx=tmp.sx;
			next.sy=tmp.sy+sz;
			s.push(next);
		}
		next.num=cnt++;
		
		//处理左下角的部分
		
		if(tmp.dx>=tmp.sx+sz&&tmp.dy<tmp.sy+sz)
		{
			next.sx=tmp.sx+sz;
			next.sy=tmp.sy;
			
			next.dx=tmp.dx;
			next.dy=tmp.dy;
			s.push(next);
		 } 
		 else
		 {
		 	map[tmp.sx+sz][tmp.sy+sz-1]=tmp.num;
		 //	map[tmp.sy+sz-1][tmp.sx+sz]=tmp.num;
		 	next.sx=tmp.sx+sz;
		 	next.sy=tmp.sy;
		 	
		 	next.dx=tmp.sx+sz;
		 	next.dy=tmp.sy+sz-1;
		 	s.push(next);
		 }
		 next.num=cnt++;
		 
		 //处理右下角
		 if(tmp.dx>=tmp.sx+sz&&tmp.dy>=tmp.sy+sz)
		 {
			next.sx=tmp.sx+sz;
			next.sy=tmp.sy+sz;
			
			next.dx=tmp.sx;
			next.dy=tmp.sy;
			s.push(next); 	
		} 
		else
		{
			map[tmp.sx+sz][tmp.sy+sz]=tmp.num;
		//	map[tmp.sy+sz][tmp.sx+sz]=tmp.num;
			next.sx=tmp.sx+sz;
			next.sy=tmp.sy+sz;
			
			next.dx=tmp.sx+sz;
			next.dy=tmp.sy+sz;
			s.push(next); 
		}
		  
		
		
	}

	
}

void display()
{
	for(int i=0;i<Max;i++)
	{
		for(int j=0;j<Max;j++)
		{
			printf("%-3d ",map[i][j]);
		}
		cout<<endl;
	}
}
int main()
{
	init();
	solve();
	display();	
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值