[ZOJ 3893][ZOJ Monthly 2015.09]B Board [构造]

博客探讨了如何使用2*3长方形和L型(n=2)构造特定形状的问题。通过分析n%3的余数情况,揭示了构造规律,并指出所有情况均可构造。文章提供了实现步骤,包括定义基本块形态、编写绘制函数和处理扩张过程。最终,给出了一组测试用例以验证解决方案的正确性。
摘要由CSDN通过智能技术生成

前面的废话不多说,直接切入正题:

为了简化这个问题,避免过于盲目的构造,我们需要考虑一下,能拼接出哪些基本块呢?


2种:2*3 长方形 和 n=2 的L型

不要看到样例给图是1、2、4就轻易猜想只有2^n才行,多多试试看嘛……

其实知道有这两种基本块,就很容易想到,n=6是可以构造的:直接18个长方形摆满就好了


看着手上有2*3,还有每边都是2的L型,一个容易想到的事情是:我可不可以在已知n=4的基础上,构造出n=6的呢?




答案:可以,在左下角用一个n=2的L型,其他位置用2*3的长方形铺设即可,如下图:


类似的(比较容易构造出来的),可以由n=6的L型得到n=8和n=10的L型:


(注意到,与n=6的情况有些差异,在左上角和右下角的2*3的长方形交界处)


(注意到,这个形态是最特别的,左上角、左下角、右下角都是n=2的L型,剩余空白用2*3的长方形填充)


之后你会发现,构造n=12、14、16的方法又是上面的循环……

为什么呢?

首先,这个L形是关于左下角与L型的右上角缺口的连线的轴对称图形,为了方便说明,我们只说明最上面和最左面的规律。

考虑扩展后的n,其n%3的情况:

n%3==0:最上面直接用2*3的长方形长边塞满(能被整除),对左面来说,剩下的长度为2*n-2,模3余1,刚好用一个n=2的L形来填充,剩下的空位用2*3的长方形塞满

n%3==2:最上面直接用2*3的长方形长边塞不满,余2,用2*3长方形的短边填充,对左面来说,剩下的长度为2*n-3,模3余1,还是用一个n=2的L形来填充,剩下的空位用2*3的长方形塞满

n%3==1:最上面直接用2*3的长方形长边塞不满,余1,这次只能用n=2的L型放上去,余0,再用2*3的长方形填充,对左面来说,剩下的长度为2*n-4,模3余1,还是用一个n=2的L形来填充,剩下的空位用2*3的长方形塞满


好像,构造规律总结出来了?

显然,这些规律对n==1、3、5、7这些奇数也都适用!!


所以,这个问题没有impossible的情况,全部可构造!

只要在最内部填上n=1或n=2的L型,不停向外+2扩展即可。


帮人帮到底,送佛送到西。

这样难度的构造其实只要专门拉个人出去想,绝对想得出来的。(于是全场我埋头坑B,队友拼命搞别的题了)

实现呢?

首先,放上5种基本块的形态:2*3长方形的横向和纵向,还有n=2的L型的3种旋转(有一种在我们的构造方案里是没用的)。

之后写个函数,把基本块形态正确的画到结果的图纸上。

然后先写主函数,估算最中心位置,然后每次往外扩张2(留个函数名在那里,先不急)并调整绘制的左上角位置与n值,顺带写好输出。

最后,深呼吸,最麻烦的部分,往外扩张2的函数。

根据n%3的情况分类讨论。

对于放置L型方块,比较简单,确定位置画下去就行,不会平移。

对于2*3长方形,推荐预先在草稿纸上画上图,计算完初始偏移量,停止的边界条件(怕犯错,再写上每步的位移量),然后写到代码里。

最后,把n=1、2、3、4、5、6、7、8全部输进去,检查一下,没问题了,那就真的过了


代码如下:

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
using namespace std;
typedef long long ll;

const int shape[5][4][4]={{
{1,1,2,0},
{1,2,2,0},
{0,0,0,0},
{0,0,0,0}
},{
{1,1,0,0},
{1,2,0,0},
{2,2,0,0},
{0,0,0,0}
},{
{1,1,0,0},
{1,2,0,0},
{3,2,2,4},
{3,3,4,4}
},{
{1,1,3,3},
{1,2,2,3},
{4,2,0,0},
{4,4,0,0}
},{
{0,0,2,2},
{0,0,1,2},
{4,1,1,3},
{4,4,3,3}
}
};

int lastid;

int mp[2010][2010];
void paintDown(int type,int fx,int sx,int sy){
	int sid=fx;
	if(type==1)sid+=2;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			if(shape[sid][i][j])
				mp[sx+i][sy+j]=lastid+shape[sid][i][j];
		}
	}
	lastid+=(type==0?2:4);
}

void twoBigger(int sx,int sy,int len){
	int px,py;
	if(len%3==0){
		for(px=0,py=0;py<len;py+=3) paintDown(0,0,sx+px,sy+py);
		for(px=2*len-2,py=4;py<2*len-2;py+=3) paintDown(0,0,sx+px,sy+py);
		for(px=2,py=0;px<2*len-4;px+=3) paintDown(0,1,sx+px,sy+py);
		for(px=len,py=2*len-2;px<2*len;px+=3) paintDown(0,1,sx+px,sy+py);
		paintDown(1,0,sx+2*len-4,sy);
	}else if(len%3==1){
		for(px=0,py=4;py<len;py+=3) paintDown(0,0,sx+px,sy+py);
		for(px=2*len-2,py=4;py<2*len-4;py+=3) paintDown(0,0,sx+px,sy+py);
		for(px=4,py=0;px<2*len-4;px+=3) paintDown(0,1,sx+px,sy+py);
		for(px=len,py=2*len-2;px<2*len-4;px+=3) paintDown(0,1,sx+px,sy+py);
		//printf("%d\n",lastid);
		paintDown(1,1,sx,sy);
		paintDown(1,0,sx+2*len-4,sy);
		paintDown(1,2,sx+2*len-4,sy+2*len-4);
		
	}else{
		for(px=0,py=2;py<len;py+=3) paintDown(0,0,sx+px,sy+py);
		for(px=2*len-2,py=4;py<2*len;py+=3) paintDown(0,0,sx+px,sy+py);
		for(px=0,py=0;px<2*len-4;px+=3) paintDown(0,1,sx+px,sy+py);
		for(px=len,py=2*len-2;px<2*len-2;px+=3) paintDown(0,1,sx+px,sy+py);
		paintDown(1,0,sx+2*len-4,sy);
	}
}

int main(){
	int n;
	while(~scanf("%d",&n)){
		memset(mp,0,sizeof(mp));
		int sx,sy,len;
		if(n&1){
			sx=sy=n;
			mp[sx][sy]=mp[sx+1][sy]=mp[sx+1][sy+1]=1;
			lastid=1;
			len=1;
		}else{
			lastid=0;
			sx=sy=n-1;
			paintDown(1,0,sx,sy);
			len=2;
		}
		while(len<n){
			len+=2;
			sx-=2;
			sy-=2;
			twoBigger(sx,sy,len);
		}
		
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				printf(j==1?"%d":" %d",mp[i][j]);
			}
			puts("");
		}
		for(int i=n+1;i<=2*n;i++){
			for(int j=1;j<=2*n;j++){
				printf(j==1?"%d":" %d",mp[i][j]);
			}
			puts("");
		}
	}
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值