![bcb45c3340dd296b4aaae3c9ebd3933f.png](https://img-blog.csdnimg.cn/img_convert/bcb45c3340dd296b4aaae3c9ebd3933f.png)
思路:
遍历矩阵上的每个点,如果这个点是1,我们就让这个点进入一个感染函数。
这个感染函数能够感染这个点周围四个方向的所有是1的点,让他的值变成2.
然后让岛的数量加1。
这个函数是递归的,如果这个点的值不是1,就不感染直接跳出。
#include <iostream>
using namespace std;
const int N = 10010;
void infect(int a[N][N], int i,int j,int row, int column) {
if (i >= row || j >= column || i < 0 || j < 0 || a[i][j] != 1) return;
a[i][j] = 2;
infect(a, i - 1, j, row, column);
infect(a, i + 1, j, row, column);
infect(a, i , j - 1, row, column);
infect(a, i , j +1, row, column);
}
int countislands(int a[N][N], int row, int column) {
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
if (a[i][j] == 1) {
infect(a,i,j, row, column);
}
}
}
}
这是单CPU,单内存的方式。
如果我们把这个矩阵分成两部分。
左边右边同时进行判断岛的数量,这样可以提高运行效率。
多CPU,并行的操作方式。
但是,这样做的话,面临合并两边需要减少岛的数量,因为有些在边界的元素可能会组成一个岛,但是在计算时两边都计算了。
因此,我们面临的问题是:
如何解决合并时边界的岛判断问题
这时候并查集结构就派上用场了。
分析这个问题的本质就是,当我们遇到左部分的有边界上有1,右边界的左部分有1,这时候就需要合并减少岛的数量。
不妨把每个岛的第一个感染的元素当成这个岛的代表点。
在同一个岛的元素,就可以当成一个集合了。这个集合有一个代表点。
当遇到需要减少岛数量的时候,先判断是否是一个集合,如果是,就说明这两个岛之前合并过,已经减过1了,不需要再减了不是一个集合,我们就减少,然后将这两边的两个岛合并,组成一个集合。
然后再遇到需要减少岛的时候继续减少,然后再合并。
这样就避免了多减的问题。
当分成小块,我们只需要把边界 改成四面八方的边界点,就可以了。