这里写自定义目录标题
更多精彩内容
这里是带你游历编程世界的Dashcoding编程社,我是Dash/北航硕士/ICPC区域赛全国排名30+/给你呈现我们眼中的世界!
256题算法特训课,帮你斩获大厂60W年薪offer
原题
米哈游校招真题RGB矩阵
B站动画详解
问题分析
这道题目要求我们计算在一个由红色(R)、绿色(G)和蓝色(B)三种颜色组成的矩阵中,由于小明的视觉缺陷导致他无法区分蓝色和绿色,进而影响他对矩阵连通块数量的判断。具体来说,连通块是指颜色相同且上下左右相邻的格子集合。我们需要计算小明视角下的连通块数量与实际连通块数量的差值。
解决这个问题的思路可以分为两步:
- 计算实际的连通块数量:首先,在不考虑小明的视觉缺陷情况下,使用深度优先搜索(DFS)算法遍历整个矩阵,统计实际的连通块数量。
- 模拟小明的视角:由于小明无法区分绿色和蓝色,我们将矩阵中所有的绿色(G)转换为蓝色(B),然后再次使用DFS统计在这种情况下的连通块数量。通过比较实际的连通块数量和小明视角下的连通块数量,我们可以得到小明视角比实际少的连通块数量。
深度优先搜索(DFS)适合这种图遍历问题,它通过递归的方式遍历所有相邻的相同颜色的格子,直到整个连通块被完全标记为已访问。该算法能够保证所有连通块被正确识别并统计。
思路分析
在这个问题中,我们需要进行两次深度优先搜索(DFS)来解决问题。首先,遍历整个矩阵,对每一个尚未访问的格子进行DFS,将该格子所在的整个连通块标记为已访问,并统计连通块的数量。这一步统计的是实际情况下的连通块数量。
然后,我们将所有的绿色(G)格子转换为蓝色(B),再进行一次DFS遍历,计算小明视角下的连通块数量。因为在小明的视角中,绿色和蓝色无法区分,所以在第二次遍历时,这两种颜色会被视为同一种颜色,导致连通块数量减少。
具体的DFS过程是从一个未访问的格子出发,递归地访问与该格子上下左右相邻且颜色相同的所有格子,直到整个连通块被标记为已访问。每次找到一个新的未访问格子时,就意味着发现了一个新的连通块。
最后,将实际的连通块数量减去小明视角下的连通块数量,即为答案。
算法实现
dx
和dy
数组表示上下左右四个方向的位移,用于在 DFS 中扩展到相邻格子。dfs
函数是深度优先搜索的核心,通过递归访问所有相邻且未访问的相同颜色的格子。query
函数遍历整个矩阵,统计未访问的连通块数量,每次发现一个新的连通块时调用dfs
进行标记。- 主函数中首先进行第一次
query
来统计实际的连通块数量。然后将所有的绿色格子转换为蓝色,再进行一次query
来统计小明视角下的连通块数量,最后输出两者的差值。
代码详解
标准代码程序
C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int n, m;
char a[N][N];
bool used[N][N];
int dx[4] = {
1, -1, 0, 0};
int dy[4] = {
0, 0, 1, -1};
// 深度优先搜索函数
void dfs(int x, int y, char c) {
used[x][y] = true;
for (int k = 0; k < 4; k++) {
int i = x + dx[k], j = y + dy[k];
if (i < 0 || i >= n || j < 0 || j >= m || used[i][j] || a[i][j] != c)
continue;
dfs(i, j, c);
}
}
// 计算连通块数量
int query() {
int num = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (!used[i][j]) {
dfs(i, j, a[i][j]);
num++;
}
}
}
return num;
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++)
cin >> a[i];
int num1 = query(); // 实际连通块数量
// 重置used数组
memset(used, 0, sizeof(used));
// 将所有绿色格子转换为蓝色
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a[i]<