求01矩阵的连通域(c++版本)

举例

求下面矩阵的四连通域
[ 1 1 0 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 ] (3) \left[ \begin{matrix} 1 & 1 & 0 & 0 & 0 \\ 1 & 0 & 1 & 0 & 0 \\ 0 & 1 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 1\\ \end{matrix} \right] \tag{3} 1100010100011000001000001(3)

结果

结果应该是有4个四连通域,分别是
左上角的三个1, 稍靠右的三个1. 右下角的两个1,总共四个四连通域。

如何使用c++代码得到结果

可以使用BFS广度优先遍历得到结果

思路
  1. 先访问左上角的1,发现其可以被加入连通域,
  2. 然后访问该元素的四邻域,如果有1的话,就加入到相同的连通域中
  3. 对目前连通域的其他元素进行相似的操作
实际代码实现

通常BFS都用 queue来实现,leetcode上有很多这样的题目。代码框架是:

vector<int> tmp; //结果
vector<int> mask  // 用于不再访问之前访问过的元素
queue<int>  q;  //用于存储当前的连通域
q.push(...);  //将第一个合适的解压入
while(! q.empty())
{
    int t = q.front();
    q.pop();
    if(t == 你想要的结果)
    { 
        tmp.push_back(...)
        mask[... ] = true;
    }
    if( mask[ i+1] == false)  //保证访问的元素之前没有访问过,如果合适,就加入到队列中
    	q.push(...)
}

另外一种框架是 : (我觉得这种框架更好,其会在访问某一层后记录step,这就是好处)

void BFS(Node start, Node target)
{
	queue<int> q;
	set<int> visited;
	q.push(start);
	visited.insert(start);
	int step = 0;

	while (q not empty) {
		int sz = q.size();
		// 处理这一整层的node
		for (int i = 0; i < sz; i++) {       
			int qnode = q.front();
			q.pop();
			if (qnode == target) {
				return target;
			}
			for (int adj : qnode.adj()) {
				if (adj is not visited) {
					q.push(adj);
					visited.insert(adj);
				}
			}
		}
		step++;
	} 
}

完整代码

#include <iostream>
#include <vector>
#include <queue>

using namespace  std;

struct Point
{
    int r;
    int c;
    Point(int r_, int c_) : r(r_), c(c_){}
    Point(const Point& p) : r(p.r), c(p.c){}
};

class Solution
{
public:
    int m;
    int n;
    //判断索引点不要越界,该点之前没有访问过,该点是有效的点
    bool isvalid(int i, int j, vector<vector<int>>& matrix, vector<vector<bool>>& mask)
    {
        return i>=0 && i<m && j>=0 && j<n && !mask[i][j] && matrix[i][j]==1;
    }
   //将合适的点加入到队列中,并标记其被访问过
    void add(int i, int j, vector<vector<int>>& matrix, queue<Point>& q, vector<vector<bool>>& mask)
    {
        if(isvalid(i, j, matrix, mask))
        {
            q.push(Point(i,j));
            mask[i][j]=true;
        }
    }
    //主代码,两重for循环+一个queue
    vector<vector<Point>> bwlabel(vector<vector<int>> &matrix)
    {
        m=matrix.size(); 
        n=matrix[0].size();
        vector<vector<Point>> res;
        vector<Point> tmp;
        vector<vector<bool>> mask(m, vector<bool>(n,false));
        for(int i=0; i<m;i++)
        {
            for(int j=0; j<n; j++)
            {
                if(mask[i][j] || matrix[i][j] == 0)
                    continue;
                tmp.clear();
                queue<Point> q;
                q.push(Point(i,j));
                mask[i][j] = true;
                while(!q.empty())
                {
                    Point t = q.front();
                    q.pop();
                    tmp.push_back(t);
                    //根据四邻域定义得来
                    add(t.r-1, t.c, matrix, q, mask);
                    add(t.r+1, t.c, matrix, q, mask);
                    add(t.r, t.c-1, matrix, q, mask);
                    add(t.r, t.c+1, matrix, q, mask);
                }
                res.push_back(tmp);
            }
        }
        return res;
    }
};
int main()
{
    vector<vector<int>> m = {
        {1,1,0,0,0},
        {1,0,1,0,0},
        {0,1,1,0,0},
        {0,0,0,1,0},
        {0,0,0,0,1},
        {0,0,0,0,0}
    };
    vector<vector<int>> n = {{}};
    Solution s;
    vector<vector<Point>> res = s.bwlabel(m);
    vector<vector<Point>> rss = s.bwlabel(n);
    return 0;
}
  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值