LeetCode 547 省份数量(图论复习:BFS、DFS、并查集)

这篇博客介绍了三种图论算法——深度优先搜索(DFS)、广度优先搜索(BFS)和并查集——在求解图中连通分量个数问题上的应用。通过实例代码详细阐述了每种方法的实现过程,帮助读者理解如何利用这些算法解决实际问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是一道经典的关于图论的联通分量的问题。
题干如下:
在这里插入图片描述
把n个城市和它们之间的关系看成图,城市是图中的节点。城市之间的相连关系看成图的边。题干中给出的isConnected矩阵就是典型的图论的邻接矩阵表示法,题干中要求得省份数量也就是图中的连通分量个数。
统计图的连通分量个数,可以使用深度优先搜索,广度优先搜索和并查集。

深度优先搜索(DFS):

class Solution {
public:  //方法1:深度优先搜索
    int findCircleNum(vector<vector<int>>& isConnected) {
        int n  = isConnected.size();
        vector<int> visited(n,0);  //记录图中的节点是否已经访问
        int circles = 0;  //记录连通分量个数
        for(int i = 0;i<n;i++){
            if(!visited[i]){  //如果该节点未访问,则从该城市进行DFS,把该节点所在连通分量的所有节点都访问了
                dfs(isConnected,visited,n,i);  //进行DFS
                circles++;
            }
        }
        return circles;
    }

    void dfs(vector<vector<int>>& isConnected,vector<int>& visited, int n, int i){
        for(int j = 0;j<n;j++){
            if(isConnected[i][j]&&!visited[j]){  //如果当前节点为访问并且与节点i相连
                visited[j] = 1;   //已经访问标记
                dfs(isConnected,visited,n,j);  //递归
            }
        }
    }
};

广度优先搜索(BFS):

class Solution {
public:  //方法2:广度优先搜索
    int findCircleNum(vector<vector<int>>& isConnected) {
        int n = isConnected.size();
        vector<int> visited(n,0);   //标记节点是否被访问
        queue<int> q;   //广度优先搜索使用队列数据结构
        int circles = 0;
        for(int i = 0;i<n;i++){
            if(!visited[i]){ //如果该节点未被访问,从该节点开始进行BFS,访问该节点所在连通分量的所有节点
                q.push(i);  //加入队列
                while(!q.empty()){  //队列未空,表示该连通分量还有节点未被访问
                    int j = q.front();  
                    q.pop();   //弹出队列
                    visited[j] = 1;  //已经访问标记
                    for(int k = 0;k<n;k++){   //访问该节点的相邻节点
                        if(isConnected[j][k] == 1&&visited[k]!=1){ //如果邻节点还没有被访问,邻节点表示isConnected为1
                            q.push(k); //加入队列
                        }
                    }
                }
                circles++;  //连通分量+1
            }
        }
        return circles;
    }
};

并查集:

class Solution {
public:  //方法3:并查集
    int findRoot(vector<int>& parent, int x){  //寻找根节点,带路径压缩
        return parent[x] == x? x : parent[x] = findRoot(parent,parent[x]);
    }

    void Union(vector<int>& parent, int x1, int x2){  //把两个节点连接到同一个连通分量
        int p1 = findRoot(parent,x1);
        int p2 = findRoot(parent,x2);
        parent[p1] = p2;
    }

    int findCircleNum(vector<vector<int>>& isConnected) {
        int n = isConnected.size();
        vector<int> parent(n,0);
        for(int i = 0;i<n;i++){  //初始时,各个节点都独立
            parent[i] = i;
        }
        int circles = 0;
        for(int i = 0;i<n;i++){
            for(int j = i+1;j<n;j++){
                if(isConnected[i][j]){  //如果i,j相连,那么它们属于同一个连通分量,那么久union它们
                    Union(parent,i,j);
                }
            }
        }
        for(int i = 0;i<n;i++){
            if(parent[i] == i) //如果根节点是自己,就是一个连通分量
                circles++;
        }
        return circles;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值