这是一道经典的关于图论的联通分量的问题。
题干如下:
把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;
}
};