Problem: Given a matrix, each cell of the matrix is either "1" or "0". Consider that all the adjacent "1" form a group, find out how many such groups are in the matrix. By"adjacent", we mean a cell's left, right, up and down. The diagonal is not considered as "adjacent". For example, if we have a matrix as follow:
1 0 0 1
1 1 0 1
0 1 1 1
1 0 0 0
then the output will be 2. There are two groups of "1" here.
Solution: This is where
disjoint-set can help. The algorithm is outlined as below:
- Basically, we scan the matrix row by row and from left to right. We need some auxiliary data structure stat[][] to keep some states. The states include the parent of a cell (it actually means which group a cell belongs to and each group has one unique parent) and the group id.
- Once we encounter a cell with value "1", if we find it is left and up neighbors are both "0", then we can create a new group, and this cell also becomes the parent of the group.
- If we find its left neighbor is "1" and up neighbor is "0", then the current cell belongs to the same group where its left neighbor is. Similarly, if we find its left neighbor is "0" and up neighbor is "1", then the current cell belongs to the same group where its up neighbor is.
- If we find both its left neighbor and up neighbor are "1", we need to do some Union() operation. First we need to find which group has a smaller group id between its left neighbor's group and up neighbor's group. Then we make the parent of the group that has a bigger id point to the parent of the group that has a smaller id. By doing this, we actually merge the two groups together and decrease the total number of groups by 1. If two groups have the same id, we don't need to do the Union().
- We can also do some optimization such as path compression. Here we actually use a simplified disjoint-set approach. The total time complexity is close to O(M*N) where M and N are the dimensions of the matrix.
The code is as below:
typedef struct cell
{
int value;
pair parent;
}cell;
pair<int, int> parent(int x, int y, cell stat[][M])
{
//here we also implemented path compression
if(stat[x][y].parent.first!=x || stat[x][y].parent.second!=y)
{
stat[x][y].parent = parent(stat[x][y].parent.first, stat[x][y].parent.second, stat);
}
return stat[x][y].parent;
}
int group_of_1(int a[][M])
{
cell stat[N][M];
int group = 0;
for(int i=0; ilt;N; i++)
for(int j=0; jlt;M; j++)
{
if(a[i][j])
{
int g1,g2;
g1 = g2 = -1;
pair<int, int> p1, p2;
if(i>0 && a[i-1][j])
{
p1 = parent(i-1, j, stat);
g1 = stat[p1.first][p1.second].value;
}
if(j>0 && a[i][j-1])
{
p2 = parent(i, j-1, stat);
g2 = stat[p2.first][p2.second].value;
}
if(g1<0 && g2<0)
{
group++;
stat[i][j].value = group;
stat[i][j].parent = pair<int, int>(i,j);
}
if(g1<0 && g2 > 0) stat[i][j].parent = p2;
if(g1>0 && g2<0) stat[i][j].parent = p1;
if(g1>0 && g2 > 0)
{
stat[i][j].value = g1 < g2 ? g1:g2;
if(g1<=g2)
stat[p2.first][p2.second].parent = stat[i][j].parent = p1;
if(g1>g2)
stat[p1.first][p1.second].parent = stat[i][j].parent = p2;
if(g1!=g2) group--;
}
}
}
return group;
}