学习C++从娃娃抓起!记录下USACO(美国信息学奥赛)备考青铜组别比赛学习过程中的题目,记录每一个瞬间。
附上汇总贴:USACO历年青铜组真题解析 | 汇总-CSDN博客
邮票画是在 N×N 画布上的黑白画,其中某些单元被涂上墨水,而其他单元则是空白。它可以用一个 N×N 的字符数组来描述 (1≤N≤20)。如果画布在该方格含有墨水,则数组中第i行的第j列为 *,否则等于 .。
Bessie有一幅邮票画,她想创作,所以农夫John借给她一张 K×K(1≤K≤N) 的邮票来做,还有一张空的 N×N 的帆布。Bessie可以重复地将邮票顺时针旋转90∘90∘ 。并在网格上的任何地方涂墨,只要涂墨的地方完全在网格内。为了涂墨,Bessie选择整数 i,j ,使 i∈[1,N−K+1] and j∈[1,N−K+1];对于每一个 (i′,j′) 使 1≤i′,j′≤K。
Bessie可以在两次盖章之间的任何时候旋转印章。一旦邮票画被涂成黑色,它就一直是黑色的。
农民John想知道Bessie是否有可能用他的邮票创造出她想要的邮票画。对于 T(1≤T≤100) 的每一个测试案例,帮助农夫John回答这个问题。
【输入】
The first line of input contains T, the number of test cases.
Each test case starts with an integer N followed by N lines, each containing a string of *s and .s, representing Bessie's desired stamp painting. The next line contains K and is followed by K lines, each containing a string of *s and .s, representing Farmer John's stamp.
Consecutive test cases are separated by newlines.
【输出】
For each test case, output YES or NO on separate lines.
【输入样例】
4
2
**
*.
1
*
3
.**
.**
***
2
.*
**
3
...
.*.
...
3
.*.
...
...
3
**.
.**
..*
2
.*
*.
【输出样例】
YES
YES
NO
YES
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int t, n, k;
char a1[25][25], a2[25][25], b1[25][25], b2[25][25], b3[25][25], b4[25][25];
void paint(char a[][25], char b[][25], char a2[][25]) // 定义对比并画画的自定义函数
{
for (int i=0; i<n-k+1; i++) { // a1矩阵的顶点坐标i和j,从0 - n-k+1
for (int j=0; j<n-k+1; j++) {
int mark = 1; // 定义标记位mark,初始为1
for (int x=i; x<i+k; x++) { // 遍历画布中邮票大小的区域
for (int y=j; y<j+k; y++) {
if (b[x-i][y-j]=='*' && a[x][y]!='*') { // 该区域与邮票对比(使用x-i和y-j,保证邮票的坐标永远是0,0 0,1 1,0 1,1),对于邮票中的'*',如果目的邮票画对应的位置也为'*'
mark = 0; // 修改标记位为0
break; // 退出循环
}
}
if (mark==0) break; // 如果mark为0,退出循环
}
if (mark == 1) { // 如果mark为1
for (int x = i; x<i+k; x++) { // 遍历画布中邮票大小的区域
for (int y=j; y<j+k; y++) {
if (b[x-i][y-j]=='*' && a2[x][y]=='.') { // 对于邮票涂墨且画布中空白的地方
a2[x][y] = b[x-i][y-j]; //在画布的对应位置涂成黑色
}
}
}
}
}
}
}
int main()
{
cin >> t; // 输入t组数据
while (t--) { // 遍历t组数据
cin >> n; // 输入n
for (int i=0; i<n; i++) { // 输入n*n的邮票画
for (int j=0; j<n; j++) {
cin >> a1[i][j];
}
}
cin >> k; // 输入k
for (int i=0; i<k; i++) { // 输入k*k的邮票
for (int j=0; j<k; j++) {
cin >> b1[i][j];
}
}
for (int i=0; i<k; i++) { // 旋转90度
for (int j=0; j<k; j++) {
b2[i][j] = b1[k-1-j][i];
}
}
for (int i=0; i<k; i++) { // 再旋转90度(相当于原有邮票旋转180度)
for (int j=0; j<k; j++) {
b3[i][j] = b2[k-1-j][i];
}
}
for (int i=0; i<k; i++) { // 再旋转90度(相当于原有邮票旋转270度)
for (int j=0; j<k; j++) {
b4[i][j] = b3[k-1-j][i];
}
}
memset(a2, '.', sizeof(a2)); // 每次初始化n*n的画布
paint(a1, b1, a2); // 用b1去比对a1,并画画
paint(a1, b2, a2); // 用b2去比对a1,并画画
paint(a1, b3, a2); // 用b3去比对a1,并画画
paint(a1, b4, a2); // 用b4去比对a1,并画画
int mark = 0; // 定义mark标记位
for (int i=0; i<n; i++) { // 检查a1与a2是否完全匹配
for (int j=0; j<n; j++) {
if (a1[i][j]==a2[i][j]) mark = 1; // 匹配时mark标记为1
else {
mark = 0; // 如果遇到有个不匹配的,mark修改为0
break; // 并退出循环
}
}
if (mark==0) break; // 如果mark为0,再退出外部循环
}
if (mark==1) cout << "YES" << endl; // 最后mark为1就输出YES
else cout << "NO" << endl; // 否则输出NO
}
return 0;
}
【运行结果】
4
2
**
*.
1
*
YES
3
.**
.**
***
2
.*
**
YES
3
...
.*.
...
3
.*.
...
...
NO
3
**.
.**
..*
2
.*
*.
YES