刷题打卡 | 插头(暴力搜索)

175 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

第十三届蓝桥杯省赛模拟赛第八题

试题:插头

题目描述

小蓝有一个插板,形状用一个 nm 的矩阵表示,0 表示板面,1 表示插孔。
小蓝还有一个插头,形状用一个 r
c 的01矩阵表示,0 表示没有伸出的部分,1 表示伸出的部分,1 表示伸出的部分。插头伸出的部分必须插在插孔里面。
为了安全,插头插到面板上不能有任何部分超过插板边界(包括没有伸出的部分)。
插头和插板都不能旋转,也不能翻转,请求出插头插入插板的合理位置。

输入格式

输入的第一行包含两个整数n,m.
接下来 n 行,每行一个长度为 m 的01串,表示插板的形状。
接下来一行包含两个整数r ,c.
接下来r 行,每行一个长度为c的01串,表示插头的形状。

输出格式

如果插头没办法安全插入插板中,输出"NO". 否则输出两个数a ,b, 表示插头的第一行第一列对应插板的第a行第b列。如果有多种情况满足要求,输出a最小的方案,如果a最小的方案有多个,输出在a最小的前提下b最小的方案。

样例输入

3 4
0110
0000
0000
3 3
000
010
000

样例输出

NO

样例输入

4 7
1110100
1101111
0001111
0000011
2 3
111
011

样例输出

2 4

评测用例规模与约定

对于50%的评测用例,2<=n,m,r,c<=20. 对于所有评测用例 2<=n,m,r,c<=100.

思路分析

这道题看起来比较复杂,实际上暴力搜索也能求解,,枚举两个矩阵
时间复杂度为O(n^4),这是由于数据量比较小的缘故.两个矩阵的行列最大也只有100\

我的思路是枚举两轮
第一轮我们先从插板的左上角开始枚举,如图

无标题.png 然后第二轮就是枚举插头,把插头的左上角一个一个地和第一轮遍历区域配对,判断所有插头伸出部分是否都能插进插板,我是用一个ok函数进行判断,如果插头伸出部分插不进就不行,if (a[x+i][y+j] == '0' && b[i][j] == '1') 就不行。 无标题.png 值得注意的一点是,如果插头能插进去,最后要输出的是插头的左上角,要加上1,因为我开的数组是从0开始记录的。

AC代码

#include<iostream>
using namespace std;
int n, m,r,c;
char a[100][100], b[100][100];
bool  ok(int x, int y)
{
	for (int i = 0; i < r; i++)
            for (int j = 0; j < c; j++)
            {
                  if (a[x+i][y+j] == '0' && b[i][j] == '1')
			return 0;
            }
	return 1;
}
int main()
{
	cin >> n >> m;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			cin >> a[i][j];
	cin >> r >> c;
	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
			cin >> b[i][j];
	for (int x = 0; x < n - r; x++)
            for (int y = 0; y < m - c; y++)
            {
		if (ok(x, y))//判断是否能
		{
			cout << x + 1 << ' ' << y + 1;
			return 0;
		}
            }
	cout << "NO";
	return 0;
}

总结

这道题咋一看复杂,但细心审题就能发现暴力枚举也能解决。
以后我刷题会少刷一些简单题,尽量系统化刷题,不再那么追求刷题量了。