ABC307C题解

ABC307C Ideal Sheet

Link

题意很简单,是一道简单的模拟题。

本题解侧重代码的实现。

前置知识

  1. C++ 中基于范围的 for 循环

  2. C++ 中 vector 的使用,以及二维 vector 的读入与遍历。

  3. C++ 中引用的基本应用。

在了解这些知识后,我们尝试使用 vector 来读入一个 \(n\)\(m\) 列的二维地图。


int n, m;
scanf("%d%d", &n, &m);

vector <vector<char>> A(n);

for (auto &v : A)
{
    v.resize(m);
    for (auto &c : v)   scanf(" %c", &c);
}

可以将上述代码中容器 A 的定义理解为定义了 \(n\) 个 vector 容器。在外层循环中每次取出一个 vector,并调整这个 vector 的大小,相当于遍历地图的每一行。然后在内层循环中每次取出一个 char 类型的元素读入。

在自定义函数中传递 vector 可以用引用。接下来我们来看具体实现。

实现思路

首先观察到所有的薄片的长宽都很小,考虑创建一个 \(30 \times 30\) 的空白地图 \(C\),行列下标都从 \(0\) 起始。我们将高桥最终想要的地图固定在地图中央,即图形 \(X\) 的左上角位于 \(C\)\((10, 10)\) 处。

接着考虑枚举 \(A\)\(B\) 薄片左上角在 \(C\) 中的位置,最终判断是否合法即可。

读入时,由于三个薄片的读入格式相同,可以用一个 read 函数来减少码量,具体实现如下。

void read(int &h, int &w, vector <vector <char>> &M)
{
	scanf("%d%d", &h, &w);
	M.resize(h);
	for (auto &s : M)
	{
		s.resize(w);
		for (auto &c : s)	scanf(" %c", &c);
	}
}

接着枚举 \(A\)\(B\) 左上角在 \(C\) 中的位置。在每次枚举时都要初始化 \(C\),代码如下,其中 \(N\) 为常量,代表 \(C\) 的大小。

void init(vector <vector <char>> &C)
{
	C.resize(N);
	for (auto &s : C)
	{
		s.resize(N);
		for (auto &c : s)	c = '.';
	}
}

再将 \(A\)\(B\) 分别粘贴到 \(C\) 中,可以写一个 fill 函数减少码量。其中 pq 是要粘贴的小薄片左上角在 \(C\) 中的位置。

void fill(int p, int q, vector <vector <char>> M, vector <vector <char>> &C)
{
	int h = M.size(), w = M[0].size();
	for (int i = p; i < p + h; i++)
		for (int j = q; j < q + w; j++)
		{
			if (C[i][j] == '#' && M[i - p][j - q] == '.')	continue;//当前粘贴的小方格是透明的且当前要粘贴的位置已经粘贴过黑色的格子了,如果再运行下面一行就会出错		
			C[i][j] = M[i - p][j - q];	
		}
}

最后再写 check 函数判断合法性即可。其中 \(MID\) 是常量,代表高桥想要的地图左上角在 \(C\) 中的位置。

bool check(vector <vector <char>> X, vector <vector <char>> C)
{
	int h = X.size(), w = X[0].size();
	for (int i = MID; i < MID + h; i++)
		for (int j = MID; j < MID + w; j++)
		{
			if (X[i - MID][j - MID] != C[i][j])	return false;
			C[i][j] = '*';//修改 C 中黑色格子方便判断 A 和 B 中的黑格子是否用完
		}
	for (auto &s : C)
		for (auto &x : s)
			if (x == '#')
				return false;
	return true;
}

Code

posted @ 2023-10-24 22:48  蒟蒻炖蒟蒻  阅读(31)  评论(0)    收藏  举报