P10257 [COCI 2023/2024 #5] Zlagalica 题解

题目传送门

题目大意:

给你 \(n\) 块拼图,颜色为 \(b_i\),所占的行数和列数分别为 \(r_i\)\(s_i\),按照给定的顺序,以及在上一块拼图的指定方向去拼(只有向上或者向右),求最终拼出来的图案。

题目分析:

(注:下文形如 \((x,y)\) 的坐标表示第 \(x\) 行,第 \(y\) 列!)

本题为小模拟。

观察到 \(1 \leq n \leq 20,1 \leq r_i,s_i \leq 10\),数据范围较小,最大开 \(200 \times 200\) 的数组存答案即可,直接模拟摆放的操作即可。由于每次拼的拼图只会拼在上一个拼图的上面或右面且紧挨,所以可以考虑从右下角 \((200,1)\) 开始模拟,这样就不用考虑什么翻转数组之类的东西了,最后再判断该行 / 该列有拼图再开始输出即可。

这里我选择记录每个拼图的右下角,即 \((x_{now},y_{now})\),初始为 \((200,1)\)

时间复杂度:\(O(n)\)

Code:

#include<bits/stdc++.h>
using namespace std;
const int N=25;
int n,X[N*10],Y[N*10],bx,ey;//bx 开始行,ey结束列,因为从 (200,1) 开始模拟
char ans[N*10][N*10];//答案拼图
struct dat
{
	char ch;//颜色
	int x,y,u,d;//行数,列数,方向,拼在对于上一块的第d行/列
}a[N],now;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i].ch>>a[i].x>>a[i].y>>a[i].u>>a[i].d;//读入拼图
	now.x=200,now.y=1;
	memset(ans,'.',sizeof(ans));//初始化答案
	int u=0,last=0;//u为当前拼图,last为上一次的拼图,初始为0
	while(n--)
	{
		cin>>u;
		if(last)
		{
			if(a[last].u==0)//向上摆
			{
				now.x-=a[last].x;
				now.y+=a[last].d-1;
			}
			else//向右摆
			{
				now.y+=a[last].y;
				now.x+=-a[last].x+a[last].d;
			}
		}
		for(int i=now.x-a[u].x+1;i<=now.x;i++)
			for(int j=now.y;j<=now.y+a[u].y-1;j++)
				ans[i][j]=a[u].ch;//覆盖答案
		last=u;//更新上一块积木的编号
	}
	for(int i=1;i<=200;i++)
		for(int j=1;j<=200;j++)
			if(ans[i][j]=='.') X[i]++,Y[j]++;//记录该行 / 该列是否有积木
	for(int i=1;i<=200;i++)//从上往下遍历
		if(X[i]!=200)
		{
			bx=i;//记录答案开始行
			break;
		}
	for(int i=200;i>=1;i--)//从右往左遍历
		if(Y[i]!=200)
		{
			ey=i;//记录答案的结束列
			break;
		}
	printf("%d %d\n",200-bx+1,ey);//输出答案大小
	for(int i=bx;i<=200;i++)
	{
		for(int j=1;j<=ey;j++)
			printf("%c",ans[i][j]);//输出拼图图案
		printf("\n");
	} 
	return 0;
}
posted @ 2024-10-21 11:26  lunjiahao  阅读(3)  评论(0编辑  收藏  举报