矩阵印章染色
字节跳动笔试真题 4月19号 第二题
题目内容
小红拿到了一个矩阵,nnn 行 mmm 列共 n×mn \times mn×m 个小方格。小红有一个 2×22 \times 22×2 的印章,每次可以将一个2×22 \times 22×2的子矩阵染成红色,每个格子只能被染一次。小红染了若干个红色的 2×22 \times 22×2 块,并且最终保证了每个 2×22 \times 22×2 红色块都是不相邻的(如果两个红色块共用了同一个边或者同一个角,则称为两个红色块相邻)。
例如:下面矩阵为非法的,因为两个 2×22 \times 22×2 红色块相邻了(共用了同一个角):
∗∗..**..∗∗..
∗∗..**..∗∗..
..∗∗..**..∗∗
..∗∗..**..∗∗
小红忘了自己的染色过程,她拿到了一个矩阵,她想知道这个矩阵是否是按她的要求染色的?
共有 ttt 组询问。
输入描述
第一行输入一个正整数 ttt,代表询问的次数。
对于每组询问,先输入两个正整数 nnn 和 mmm,代表矩阵的行数和列数。
接下来的 nnn 行,每行输入一个长度为 mmm 的字符串。字符*代表格子被染成红色,.代表未被染色。
1≤t,n,m≤501 \le t, n, m \le 501≤t,n,m≤50
输出描述
输出 ttt 行,每行对应一组询问的答案。
若该图形是小红染色的,则输出 "YesYesYes"。否则输出"NoNoNo"。
样例1
输入
3
4 4
**..
**..
..**
..**
4 5
**...
**...
...**
...**
2 2
*.
..
输出
No
Yes
No
题解
思路
模拟
- 按照题目思路进行模拟实现即可。
- 定义
vis数组记录某个位置是否被访问,按照从上往下、从左往右方向进行遍历,如果遇到grid[i][j] == '**' and vis[i][j] = false把这个位置当作印章的左上角,并进行合法性判断- 当前位置是否允许构成
2 * 2区域 - 构成的
2 * 2区域全为红色 - 包裹当前
2 * 2区域的4 * 4区域最外边是否都不为* - 上述任意不满足返回false
- 当前位置是否允许构成
- 代码整体复杂度为
O(n * m)
C++
cpp
#include<bits/stdc++.h>
using namespace std;
bool check(vector<vector<char>>& grid) {
int n = grid.size();
int m = grid[0].size();
vector<vector<bool>> vis(n, vector<bool>(m, false));
// 枚举所有*,未vis被当作2*2的左上角
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
// 访问过或者不是染色直接跳过
if (vis[i][j] || grid[i][j] != '*') {
continue;
}
// 不能构成完整2 * 2
if (i + 1 >= n || j + 1 >= m) {
return false;
}
// 不能构成2*2染色区域
if (grid[i][j+1] != '*' || grid[i+1][j] != '*' || grid[i+1][j+1] != '*') {
return false;
}
// 更新为已经访问
vis[i][j] = vis[i][j+1] = vis[i+1][j] = vis[i+1][j+1] = true;
// 检查是否存在与当前 2 * 2相邻的染色
for (int x = i -1; x <= i + 2; x++) {
for (int y = j -1; y <= j + 2; y++) {
if (x < 0 || x >= n || y < 0 || y >= m) {
continue;
}
if (x >= i && x <= i + 1 && y >= j && y <= j + 1) {
continue;
}
// 相邻区域被染色
if (grid[x][y] == '*') {
return false;
}
}
}
}
}
return true;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
vector<vector<char>> grid(n, vector<char>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> grid[i][j];
}
}
if (check(grid)) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
}
return 0;
}
java
java
import java.io.*;
import java.util.*;
public class Main {
static boolean check(char[][] grid) {
int n = grid.length;
int m = grid[0].length;
boolean[][] vis = new boolean[n][m];
// 枚举所有*,未vis被当作2*2的左上角
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
// 访问过或者不是染色直接跳过
if (vis[i][j] || grid[i][j] != '*') {
continue;
}
// 不能构成完整2 * 2
if (i + 1 >= n || j + 1 >= m) {
return false;
}
// 不能构成2*2染色区域
if (grid[i][j + 1] != '*' ||
grid[i + 1][j] != '*' ||
grid[i + 1][j + 1] != '*') {
return false;
}
// 更新为已经访问
vis[i][j] = true;
vis[i][j + 1] = true;
vis[i + 1][j] = true;
vis[i + 1][j + 1] = true;
// 检查是否存在与当前 2 * 2相邻的染色
for (int x = i - 1; x <= i + 2; x++) {
for (int y = j - 1; y <= j + 2; y++) {
if (x < 0 || x >= n || y < 0 || y >= m) {
continue;
}
if (x >= i && x <= i + 1 &&
y >= j && y <= j + 1) {
continue;
}
// 相邻区域被染色
if (grid[x][y] == '*') {
return false;
}
}
}
}
}
return true;
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine());
while (T-- > 0) {
String[] first = br.readLine().split(" ");
int n = Integer.parseInt(first[0]);
int m = Integer.parseInt(first[1]);
char[][] grid = new char[n][m];
for (int i = 0; i < n; i++) {
String row = br.readLine();
for (int j = 0; j < m; j++) {
grid[i][j] = row.charAt(j);
}
}
if (check(grid)) {
System.out.println("Yes");
} else {
System.out.println("No");
}
}
}
}
python
python
import sys
def check(grid):
n = len(grid)
m = len(grid[0])
vis = [[False] * m for _ in range(n)]
# 枚举所有*,未vis被当作2*2的左上角
for i in range(n):
for j in range(m):
# 访问过或者不是染色直接跳过
if vis[i][j] or grid[i][j] != '*':
continue
# 不能构成完整2 * 2
if i + 1 >= n or j + 1 >= m:
return False
# 不能构成2*2染色区域
if (grid[i][j + 1] != '*' or
grid[i + 1][j] != '*' or
grid[i + 1][j + 1] != '*'):
return False
# 更新为已经访问
vis[i][j] = True
vis[i][j + 1] = True
vis[i + 1][j] = True
vis[i + 1][j + 1] = True
# 检查是否存在与当前 2 * 2相邻的染色
for x in range(i - 1, i + 3):
for y in range(j - 1, j + 3):
if x < 0 or x >= n or y < 0 or y >= m:
continue
if i <= x <= i + 1 and j <= y <= j + 1:
continue
# 相邻区域被染色
if grid[x][y] == '*':
return False
return True
data = sys.stdin.read().strip().splitlines()
idx = 0
T = int(data[idx])
idx += 1
ans = []
for _ in range(T):
n, m = map(int, data[idx].split())
idx += 1
grid = []
for _ in range(n):
grid.append(list(data[idx]))
idx += 1
if check(grid):
ans.append("Yes")
else:
ans.append("No")
print("\n".join(ans))
javascript
js
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const lines = [];
rl.on('line', line => {
lines.push(line);
});
rl.on('close', () => {
let idx = 0;
function check(grid) {
const n = grid.length;
const m = grid[0].length;
const vis = Array.from(
{ length: n },
() => Array(m).fill(false)
);
// 枚举所有*,未vis被当作2*2的左上角
for (let i = 0; i < n; i++) {
for (let j = 0; j < m; j++) {
// 访问过或者不是染色直接跳过
if (vis[i][j] || grid[i][j] !== '*') {
continue;
}
// 不能构成完整2 * 2
if (i + 1 >= n || j + 1 >= m) {
return false;
}
// 不能构成2*2染色区域
if (
grid[i][j + 1] !== '*' ||
grid[i + 1][j] !== '*' ||
grid[i + 1][j + 1] !== '*'
) {
return false;
}
// 更新为已经访问
vis[i][j] = true;
vis[i][j + 1] = true;
vis[i + 1][j] = true;
vis[i + 1][j + 1] = true;
// 检查是否存在与当前 2 * 2相邻的染色
for (let x = i - 1; x <= i + 2; x++) {
for (let y = j - 1; y <= j + 2; y++) {
if (x < 0 || x >= n || y < 0 || y >= m) {
continue;
}
if (
x >= i && x <= i + 1 &&
y >= j && y <= j + 1
) {
continue;
}
// 相邻区域被染色
if (grid[x][y] === '*') {
return false;
}
}
}
}
}
return true;
}
const T = Number(lines[idx++]);
const ans = [];
for (let t = 0; t < T; t++) {
const [n, m] = lines[idx++].split(' ').map(Number);
const grid = [];
for (let i = 0; i < n; i++) {
grid.push(lines[idx++].split(''));
}
ans.push(check(grid) ? 'Yes' : 'No');
}
console.log(ans.join('\n'));
});
Go
go
package main
import (
"bufio"
"fmt"
"os"
)
func check(grid [][]byte) bool {
n := len(grid)
m := len(grid[0])
vis := make([][]bool, n)
for i := 0; i < n; i++ {
vis[i] = make([]bool, m)
}
// 枚举所有*,未vis被当作2*2的左上角
for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
// 访问过或者不是染色直接跳过
if vis[i][j] || grid[i][j] != '*' {
continue
}
// 不能构成完整2 * 2
if i+1 >= n || j+1 >= m {
return false
}
// 不能构成2*2染色区域
if grid[i][j+1] != '*' ||
grid[i+1][j] != '*' ||
grid[i+1][j+1] != '*' {
return false
}
// 更新为已经访问
vis[i][j] = true
vis[i][j+1] = true
vis[i+1][j] = true
vis[i+1][j+1] = true
// 检查是否存在与当前 2 * 2相邻的染色
for x := i - 1; x <= i+2; x++ {
for y := j - 1; y <= j+2; y++ {
if x < 0 || x >= n || y < 0 || y >= m {
continue
}
if x >= i && x <= i+1 &&
y >= j && y <= j+1 {
continue
}
// 相邻区域被染色
if grid[x][y] == '*' {
return false
}
}
}
}
}
return true
}
func main() {
in := bufio.NewReader(os.Stdin)
var T int
fmt.Fscan(in, &T)
for ; T > 0; T-- {
var n, m int
fmt.Fscan(in, &n, &m)
grid := make([][]byte, n)
for i := 0; i < n; i++ {
var row string
fmt.Fscan(in, &row)
grid[i] = []byte(row)
}
if check(grid) {
fmt.Println("Yes")
} else {
fmt.Println("No")
}
}
}