AcWing第51场周赛——T2(4420. 连通分量)

题目描述

给定一个 n×m 的方格矩阵,每个方格要么是空格(用 . 表示),要么是障碍物(用 * 表示)。

如果两个空格存在公共边,则两空格视为相邻。

我们称一个不可扩展的空格集合为连通分量,如果集合中的任意两个空格都能通过相邻空格的路径连接。

这其实是一个典型的众所周知的关于连通分量(Connected Component )的定义。

现在,我们的问题如下:

对于每个包含障碍物的单元格 (x,y),假设它是一个空格(所有其他单元格保持不变)的前提下,请你计算包含 (x,y) 的连通分量所包含的单元格数量。

注意,所有假设求解操作之间都是相互独立的,互不影响。

输入格式

第一行包含两个整数 n,m。

接下来 n 行,每行包含 m 个字符:. 表示空格,* 表示障碍物。

输出格式

输出一个 n 行 m 列的字符矩阵,其中第 i 行第 j 列的字符对应给定矩阵中第 i 行第 j 列的单元格。如果该单元格为空格,则输出字符为 .,如果该单元格为障碍物,则输出字符为假设该单元格为空格的前提下,包含该单元格的连通分量所包含的单元格数量对 10 取模后的结果。具体格式可参照输出样例。

数据范围

前 5 个测试点满足 1≤n,m≤10
所有测试点满足 1≤n,m≤1000

输入样例1:

3 3
*.*
.*.
*.*

输出样例1:

3.3
.5.
3.3

输入样例2:

4 5
**..*
..***
.*.*.
*.*.*

输出样例2:

46..3
..732
.6.4.
5.4.3

解题思路

并查集

  1. 维护连通分量,然后枚举每一个星号,且求出该星号的四个方向的连通分量的数量和(最后不要忘了加1本身)
  2. 利用一个get方法将二维数组点的坐标映射成一个数(作为自己的父节点)——俗称矩阵展开
  3. 因为打印的数据有点多,所以这里还需要使用缓冲流进行输入输出的优化

Java代码

  1 import java.util.*;
  2 import java.io.*;
  3 
  4 /**
  5  * 并查集
  6  */
  7 public class Main {
  8 
  9     static int N = 1000 + 10;
 10     static int[] p = new int[N * N];
 11     static int[] s = new int[N * N];
 12     static int[][] g = new int[N][N];
 13     static int n, m;
 14     static int[] dx = {0, 1, 0, -1};
 15     static int[] dy = {1, 0, -1, 0};
 16     static int MOD = 10;
 17 
 18     public static int find(int x) {
 19         if (p[x] != x) {
 20             p[x] = find(p[x]);
 21         }
 22         return p[x];
 23     }
 24 
 25     public static void init() {
 26         for (int i = 1; i <= n; i++) {
 27             for (int j = 1; j <= m; j++) {
 28                 int a = get(i, j);
 29                 p[a] = a;
 30                 s[a] = 1;
 31             }
 32         }
 33     }
 34 
 35     /**
 36      * 映射二维矩阵中的横纵坐标
 37      * 
 38      */
 39     public static int get(int x, int y) {
 40         // 矩阵展开
 41         return x * m + y;
 42     }
 43 
 44     public static void main(String[] args) throws Exception {
 45         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 46         BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 47         String[] str = br.readLine().split(" ");
 48         n = Integer.parseInt(str[0]);
 49         m = Integer.parseInt(str[1]);
 50 
 51         init();
 52 
 53         for (int i = 1; i <= n; i++) {
 54             char[] c = br.readLine().toCharArray();
 55             for (int j = 1 ; j <= m; j++) {
 56                 g[i][j] = c[j - 1];
 57             }
 58         }
 59 
 60         // 预处理连通块
 61         for (int i = 1; i <= n; i++) {
 62             for (int j = 1; j <= m; j++) {
 63                 if (g[i][j] == '.') {
 64                     // 枚举四个方向
 65                     for (int k = 0; k < 4; k++) {
 66                         int x = i + dx[k];
 67                         int y = j + dy[k];
 68                         if (x >= 1 && x <= n && y >= 1 && y <= m && g[x][y] == '.') {
 69                             int a = get(i, j);
 70                             int b = get(x, y);
 71                             a = find(a);
 72                             b = find(b);
 73                             if (a != b) {
 74                                 p[a] = b;
 75                                 s[b] += s[a];
 76                             }
 77                         }
 78                     }
 79                 }
 80             }
 81         }
 82 
 83         // 枚举所有.
 84         for (int i = 1; i <= n; i++) {
 85             for (int j = 1; j <= m; j++) {
 86                 if (g[i][j] == '.') {
 87                     bw.write(".");
 88                 } else {
 89                     // 先将四个方向的祖先存储起来,然后再去重
 90                     TreeSet<Integer> fathers = new TreeSet<>();
 91                     for (int k = 0; k < 4; k++) {
 92                         int x = i + dx[k];
 93                         int y = j + dy[k];
 94                         if (x >= 1 && x <= n && y >= 1 && y <= m && g[x][y] == '.') {
 95                             int a = get(x, y);
 96                             fathers.add(find(a));
 97                         }
 98                     }
 99                     int sum = 1;
100                     while (fathers.size() > 0) {
101                         sum += s[fathers.pollFirst()];
102                     }
103                     bw.write(String.valueOf(sum % MOD));
104                 }
105             }
106             bw.newLine();
107         }
108 
109         bw.flush();
110         bw.close();
111         br.close();
112     }
113 
114 }

Acwing链接:https://www.acwing.com/problem/content/description/4423/

posted @ 2022-05-15 14:46  没有你哪有我  阅读(30)  评论(0编辑  收藏  举报