ccxk
2024-08-20
点 赞
0
热 度
74
评 论
0

Maximize the Largest Component 题解

文章摘要

智阅GPT

本题的 Easy Version 题解

提示:

题目大意

该题目要求在一个由 .# 组成的网格中,通过选择某一行或某一列,将该行或该列所有字符设置为 #,使得整个网格中 # 组成的最大连通块的大小最大化。

题目给定了多个测试用例,每个测试用例包含一个 ​n\times m 的网格,网格中的每个字符是 .#。要求我们找到执行一次操作后,# 组成的最大连通块的最大值。

解题思路

大致解题路线:
  1. BFS 搜索连通块,并记录连通块编号和大小,以备后用。
  2. ​n 行遍历找最大。
  3. ​m 行遍历找最大。

整体思路简单,但是码量十足。。。

下面是更具体的思路。

  1. 初始化和输入处理

    • 首先读取输入的网格,并初始化访问标记数组 vis,该数组用于记录每个格子是否被访问过。
    • 使用广度优先搜索 BFS 来计算原始网格中每个连通块的大小,并将这些大小记录在一个字典 tong 中。
  2. 模拟操作

    • 对于每一行,假设将整行设置为 #,计算由此形成的最大连通块。
    • 对于每一列,假设将整列设置为 #,计算由此形成的最大连通块。
    • 需要特别处理边界情况,确保相邻连通块不会因为重复计入而造成计算错误。
  3. 计算最大连通块

    • 遍历每一行和每一列,模拟将该行或该列设置为 # 后的连通块大小。
    • 最后输出所有可能结果中的最大值。

    具体操作请看下方代码。

代码实现

#include<bits/stdc++.h>
using namespace std;

const int N = 1005; // 网格的最大尺寸
int t, n, m; // t表示测试用例数量,n和m分别表示网格的行数和列数
int fx[5] = {0, 1, 0, -1, 0}; // BFS的方向数组,表示上下左右四个方向的行偏移量
int fy[5] = {0, 0, 1, 0, -1}; // BFS的方向数组,表示上下左右四个方向的列偏移量
int flag; // 连通块编号

queue<int> q1, q2; // BFS队列,分别存储行坐标和列坐标

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> t; // 读取测试用例数量
    while (t--) { 
        cin >> n >> m; // 读取当前网格的行数和列数
        vector<vector<char>> a(n + 2, vector<char>(m + 2)); // 定义网格,边界用于处理
        vector<vector<int>> vis(n + 2, vector<int>(m + 2, 0)); // 标记连通块编号
        flag = 0; // 连通块标记初始化
        map<int, int> tong; // 存储每个连通块的大小

        // 读取网格数据
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                cin >> a[i][j];
            }
        }

        // BFS计算连通块大小
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (vis[i][j] == 0 && a[i][j] == '#') { // 如果当前格子未被访问且是'#'
                    flag++; // 更新连通块编号
                    vis[i][j] = flag; // 标记当前连通块编号
                    q1.push(i);
                    q2.push(j);
                    tong[flag]++; // 初始化连通块大小

                    // BFS扩展连通块
                    while (!q1.empty()) {
                        int nx = q1.front();
                        int ny = q2.front();
                        q1.pop(); 
                        q2.pop(); 

                        for (int i = 1; i <= 4; i++) { // 遍历四个方向
                            int xx = nx + fx[i], yy = ny + fy[i];
                            if (a[xx][yy] == '#' && !vis[xx][yy] && xx <= n && yy <= m && xx >= 1 && yy >= 1) {
                                q1.push(xx);
                                q2.push(yy);
                                vis[xx][yy] = flag; // 标记相邻格子
                                tong[flag]++; // 增加连通块大小
                            }
                        }
                    }
                }
            }
        }

        int ans = 0; // 存储最大连通块大小
        map<int, int> vis2, biaoji; // 辅助标记

        // 处理每一行
        for (int i = 1; i <= n; i++) {
            int cnt = 0; // 当前行形成的连通块大小
            biaoji.clear(); 
            vis2.clear();
            for (int j = 1; j <= m; j++) {
                if (a[i][j] == '#') {
                    vis2[vis[i][j]] = 1; 
                }
                if (a[i][j] == '.') cnt++;
                else if (!biaoji[vis[i][j]]) { // 如果连通块未被标记
                    biaoji[vis[i][j]] = 1; // 标记当前连通块
                    cnt += tong[vis[i][j]]; // 累加连通块大小
                }
                if (!biaoji[vis[i - 1][j]] && a[i - 1][j] == '#' && vis[i - 1][j] != vis[i][j]) {
                    cnt += tong[vis[i - 1][j]]; // 累加上方连通块
                    biaoji[vis[i - 1][j]] = 1; 
                    if (vis2[vis[i - 1][j]] == 1) cnt--; // 避免重复计入
                }
                if (!biaoji[vis[i + 1][j]] && a[i + 1][j] == '#' && vis[i + 1][j] != vis[i][j]) {
                    cnt += tong[vis[i + 1][j]]; // 累加下方连通块
                    biaoji[vis[i + 1][j]] = 1; 
                    if (vis2[vis[i + 1][j]] == 1) cnt--; 
                }
            }
            ans = max(ans, cnt); // 更新最大连通块大小
        }

        // 处理每一列
        for (int j = 1; j <= m; j++) {
            int cnt = 0; // 当前列形成的连通块大小
            biaoji.clear(); 
            vis2.clear(); 
            for (int i = 1; i <= n; i++) {
                if (a[i][j] == '#') {
                    vis2[vis[i][j]] = 1; 
                }
                if (a[i][j] == '.') cnt++;
                else if (!biaoji[vis[i][j]]) { 
                    biaoji[vis[i][j]] = 1; 
                    cnt += tong[vis[i][j]]; 
                }
                if (!biaoji[vis[i][j - 1]] && a[i][j - 1] == '#' && vis[i][j - 1] != vis[i][j]) {
                    cnt += tong[vis[i][j - 1]]; // 累加左侧连通块
                    biaoji[vis[i][j - 1]] = 1; 
                    if (vis2[vis[i][j - 1]] == 1) cnt--; 
                }
                if (!biaoji[vis[i][j + 1]] && a[i][j + 1] == '#' && vis[i][j + 1] != vis[i][j]) {
                    cnt += tong[vis[i][j + 1]]; // 累加右侧连通块
                    biaoji[vis[i][j + 1]] = 1; 
                    if (vis2[vis[i][j + 1]] == 1) cnt--; 
                }
            }
            ans = max(ans, cnt); // 更新最大连通块大小
        }

        cout << ans << endl; // 输出最大连通块的大小
    }
    return 0;
}

复杂度分析

  • 时间复杂度:

    • 每个测试用例的时间复杂度主要分为两部分:BFS 用于找到所有的连通块,复杂度为 ​O(n \times m),而行和列的遍历为 ​O(n \times m)
    • 因此总体时间复杂度为 ​O(t \times n \times m),其中 ​t 是测试用例数。
  • 空间复杂度:

    • 额外使用了 vistong 两个数组,空间复杂度为 ​O(n \times m)

    喜欢的话不要忘记点赞哈!有任何疑问或见解欢迎在页面下方评论区发布!


用键盘敲击出的不只是字符,更是一段段生活的剪影、一个个心底的梦想。希望我的文字能像一束光,在您阅读的瞬间,照亮某个角落,带来一丝温暖与共鸣。

ccxk

站长

不具版权性
不具时效性

文章内容不具时效性。若文章内容有错误之处,请您批评指正。


目录

欢迎来到ccxk的站点,为您导航全站动态

26 文章数
5 分类数
6 评论数
15标签数
最近评论
ccxk

ccxk


hi

ccxk

ccxk


Hi

Camelaaa_

Camelaaa_


热门文章

访问统计