岛问题
题目
一个矩阵中只有0和1两种值,每个位置都可以和自己的上、下、左、右四个位置相连,如果有一片1连在一起,这个部分叫做一个岛,求一个矩阵中有多少个岛?
【举例】
001010
111010
100100
000000
这个矩阵中有三个岛
Infect
从左上到右下依次遍历所有数字
当遇到0时,不处理
当遇到1时,找到一片岛屿,进入感染流程
将它的上下左右感染成2,再把它上下左右的上下左右感染成2 。。。。
直到越界或者不为1返回
当遍历到0,2时,res=1
002010
222010
200100
000000
遍历到0,4时,res=2
002020
222020
200100
000000
遍历到2,3时,res=3
002020
222020
200200
000000
一共找到三个岛
package main
import "fmt"
func countIslands(m [][]int) int {
if m == nil || m[0] == nil {
return 0
}
N := len(m)
M := len(m[0])
res := 0
for i := 0; i < N; i++ {
for j := 0; j < M; j++ {
if m[i][j] == 1 {
res++
infect(m, i, j, N, M)
}
}
}
return res
}
func infect(m [][]int, i, j, N, M int) {
if i < 0 || i >= N || j < 0 || j >= M || m[i][j] != 1 {
return
}
m[i][j] = 2
infect(m, i, j-1, N, M)
infect(m, i, j+1, N, M)
infect(m, i-1, j, N, M)
infect(m, i+1, j, N, M)
}
func main() {
m := [][]int{
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 1, 1, 0, 1, 1, 1, 0},
{0, 1, 1, 1, 0, 0, 0, 1, 0},
{0, 1, 1, 0, 0, 0, 0, 0, 1}}
fmt.Println(countIslands(m))
}
如何设计一个并行算法解决这个问题
并查集
a b c d e 都是单独的集合
{a},{b},{c},{d},{e}
判断a b是否属于同个集合,a的father是a,b的father是b,a和b不一样,则isSameSet=false
a union b,将b的father指向a
判断{a,b}与{c}是否属于同个集合 ,{a,b}的father是a,c是c,isSameSet=false
如果我们union成一个很长的链,{a,b,c,d},这时候d找father a耗时加大,可以沿途将c d的father设置成a,扁平化处理
切割矩阵
1 1 1 1 1 1
1 0 0 0 0 1
1 0 1 1 1 1
1 0 1 0 0 0
1 0 1 1 1 1
这里其实只有一个岛
左CPU算出两个岛,右CPU算出两个岛,一共四个岛
记录边界的信息属于哪个岛
(0,2) 与 (0,3)相连,并查集判断A B不属于一个集合,
四个岛减去一个岛,变成三个岛
{A,B} {C},{D}
(2,2)与(2,3)相连,并查集判断C B 不属于一个集合
3个岛减去一个岛,变成2个岛
{A,B,C}{D}
(4,2)与(4,3)相连,并查集判断C D不属于一个集合
2个岛减去一个岛,变成一个岛
返回一个岛
将任意大的矩阵任意切割成CPU数个小矩阵,每个CPU记录岛数量与边界信息即可