【888题秋招篇】剑指大厂offer第八题,带你用深度优先搜索秒杀米哈游校招真题-RGB矩阵,斩获大厂年薪60wOffer

更多精彩内容

这里是带你游历编程世界的Dashcoding编程社,我是Dash/北航硕士/ICPC区域赛全国排名30+/给你呈现我们眼中的世界!

256题算法特训课,帮你斩获大厂60W年薪offer

原题

米哈游校招真题RGB矩阵

B站动画详解

问题分析

这道题目要求我们计算在一个由红色(R)、绿色(G)和蓝色(B)三种颜色组成的矩阵中,由于小明的视觉缺陷导致他无法区分蓝色和绿色,进而影响他对矩阵连通块数量的判断。具体来说,连通块是指颜色相同且上下左右相邻的格子集合。我们需要计算小明视角下的连通块数量与实际连通块数量的差值。

解决这个问题的思路可以分为两步:

  1. 计算实际的连通块数量:首先,在不考虑小明的视觉缺陷情况下,使用深度优先搜索(DFS)算法遍历整个矩阵,统计实际的连通块数量。
  2. 模拟小明的视角:由于小明无法区分绿色和蓝色,我们将矩阵中所有的绿色(G)转换为蓝色(B),然后再次使用DFS统计在这种情况下的连通块数量。通过比较实际的连通块数量和小明视角下的连通块数量,我们可以得到小明视角比实际少的连通块数量。

深度优先搜索(DFS)适合这种图遍历问题,它通过递归的方式遍历所有相邻的相同颜色的格子,直到整个连通块被完全标记为已访问。该算法能够保证所有连通块被正确识别并统计。

思路分析

在这个问题中,我们需要进行两次深度优先搜索(DFS)来解决问题。首先,遍历整个矩阵,对每一个尚未访问的格子进行DFS,将该格子所在的整个连通块标记为已访问,并统计连通块的数量。这一步统计的是实际情况下的连通块数量。

然后,我们将所有的绿色(G)格子转换为蓝色(B),再进行一次DFS遍历,计算小明视角下的连通块数量。因为在小明的视角中,绿色和蓝色无法区分,所以在第二次遍历时,这两种颜色会被视为同一种颜色,导致连通块数量减少。

具体的DFS过程是从一个未访问的格子出发,递归地访问与该格子上下左右相邻且颜色相同的所有格子,直到整个连通块被标记为已访问。每次找到一个新的未访问格子时,就意味着发现了一个新的连通块。

最后,将实际的连通块数量减去小明视角下的连通块数量,即为答案。

算法实现

  1. dxdy 数组表示上下左右四个方向的位移,用于在 DFS 中扩展到相邻格子。
  2. dfs 函数是深度优先搜索的核心,通过递归访问所有相邻且未访问的相同颜色的格子。
  3. query 函数遍历整个矩阵,统计未访问的连通块数量,每次发现一个新的连通块时调用 dfs 进行标记。
  4. 主函数中首先进行第一次 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]<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值