岛问题
【题目】一个矩阵中只有0和1两种值,每个位置都可以和自己的上、下、左、右四个位置相连,如果有一片1连在一起,这个部分叫做一个岛,求一个矩阵中有多少个岛?
【举例】
0 0 1 0 1 0
1 1 1 0 1 0
1 0 0 1 0 0
0 0 0 0 0 0
这个矩阵中有三个岛
void infect(vector<vector<int>>& m, int i, int j, int N, int M){
if(i < 0 || i >= N || j < 0 || j >= M || m[i][j] != 1){
return;
}
m[i][j] = 2;
infect(m, i + 1, j, N, M);
infect(m, i - 1, j, N, M);
infect(m, i, j + 1, N, M);
infect(m, i, j - 1, N, M);
}
int island(vector<vector<int>>& m){
if(m.empty() || m[0].empty()){
return 0;
}
int N = m.size();
int M = m[0].size();
int res = 0;
for(int i = 0; i < N; i++){
for(int j = 0; j < M; j++){
if(m[i][j] == 1){
res++;
infect(m, i, j, N, M);
}
}
}
return res;
}
并查集
接口:bool isSameSet(a, b) void unionSet(a, b)
初始化:
unionSet(a, b)
unionSet(b, e); unionSet(c, d);
unionSet(b, d)
优化:
在查找Y的顶部时,会把查找沿途地点直接指向顶部
解决并查集中链过长的问题,使得下次操作可以一步到位
template <typename T>
class Element{
public:
T val;
Element(T val) : val(val) {}
};
template <typename T>
class UnionFindSet{
public:
unordered_map<T, Element<T> *> elementMap;
unordered_map<Element<T>*, Element<T>*> fatherMap;
unordered_map<Element<T>*, T> sizeMap;
UnionFindSet(vector<T>& arr){
for(T i : arr){
Element<T> *temp = new Element<T>(i);
elementMap.insert(make_pair(i, temp));
fatherMap.insert(make_pair(temp, temp));
sizeMap.insert(make_pair(temp, 1));
}
}
Element<T>* findHead(Element<T> *element){
stack<Element<T>*> path;
while(element != fatherMap[element]){
path.push(element);
element = fatherMap[element];
}
while(!path.empty()){
fatherMap[path.top()] = element; path.pop();
}
return element;
}
bool isSameSet(T a, T b){
if(elementMap.find(a) != elementMap.end() && elementMap.find(b) != elementMap.end()){
return findHead(elementMap[a]) == findHead(elementMap[b]);
}
return false;
}
void unionSet(T a, T b){
if(elementMap.find(a) != elementMap.end() && elementMap.find(b) != elementMap.end()){
Element<T> *aHead = findHead(elementMap[a]);
Element<T> *bHead = findHead(elementMap[b]);
if(aHead != bHead){
Element<T> *big = sizeMap[aHead] > sizeMap[bHead] ? aHead : bHead;
Element<T> *small = big == aHead ? bHead : aHead;
fatherMap[small] = big;
sizeMap[big] += sizeMap[small];
sizeMap.erase(small);
}
}
}
};
如果并查集中有N个元素,findHead次数达到O(N)水平,单次findHead代价O(1)
【题目】
设计一个并行算法解决岛问题:
一个矩阵中只有0和1两种值,每个位置都可以和自己的上、下、左、右四个位置相连,如果有一片1连在一起,这个部分叫做一个岛,求一个矩阵中有多少个岛?
【举例】
0 0 1 0 1 0
1 1 1 0 1 0
1 0 0 1 0 0
0 0 0 0 0 0
这个矩阵中有三个岛
两个cpu:
左侧cpu找到两个岛A和B,右侧cpu找到两个岛C和D。
两cpu记录每个边界1点所对应的岛。
因此,在两个cpu各自找到两个岛后,走一遍边界节点,自上往下:
islandNum = 4;
unionSet(A, C); islandNum--;
unionSet(B, C); islandNum--;
unionSet(B, D); islandNum--;
unionSet(A, D);
多个cpu:
每个cpu找自己的岛,收集自己的四个边界的信息,最后合并