在求图的连通分量时可能会碰见的问题--已经构造出了邻接矩阵,但不知道怎么求连通分量。这里选择用BFS来求连通分量。
在开始前先要说明下一些基础知识。
连通分量
如上图图一的连通分量为1,而去掉其中一条边后可以得到图二,而图二的连通分量为2。相当于求一个图里有多少个连通图。
BFS求连通分量
假设我们现在已经得到了一个连通矩阵(如下),可以知道该图一共4个节点且存在连通分量(矩阵不全为0)。
0 1 1 0
1 0 0 0
1 0 0 0
0 0 0 0
那么思路是这样的:设置一个变量sum来记录连通分量的数量。然后去遍历这四个节点,每次遍历都去寻找它的邻边;并把在邻边上的点设置为“已访问”。在第一次遍历时如果这个节点已经被访问过了就跳过;如果没有被访问过sum就需要加一并查找该节点有没有邻边。
有了思路后就剩“如何实现查找该节点的邻边”了,用DFS和BFS都行,这里用的BFS。
其中x为节点编号,n为总的节点个数,mat为邻接矩阵,visit为记录节点是否已被访问过的数组。每次BFS时先把该节点设置为已访问并入队。然后去查找它邻边上的节点(通过遍历mat[cur]这一行,如果在cur这一行的第i个位置为1,就说明编号为cur的节点与编号为i的节点存在邻边),如果该节点没被访问过且存在邻边,入队并设置为已访问。
void BFS(int x,int n,int**mat,int*visit)
{
queue<int>Q;
Q.push(x);
visit[x] = 1;
while (!Q.empty())
{
int cur = Q.front();
Q.pop();
for (int i = 0;i < n;i++)
{
if (visit[i]==0 && mat[cur][i])
{
visit[i] = 1;
Q.push(i);
}
}
}
}
最后遍历每一个节点再根据是否已被访问去调用BFS即可。
for (int i = 0;i < n;i++)
{
if (visit[i] == 0)
{
BFS(i,n,mat,visit);
sum++;
}
}
这里放上一组实验样例来供各位测试。
输入样例
3
4 A B C D
2
A B
A C
6 V1 V2 V3 V4 V5 V6
5
V1 V2
V1 V3
V2 V4
V5 V6
V3 V5
8 1 2 3 4 5 6 7 8
5
1 2
1 3
5 6
5 7
4 8
输出样例
A B C D
0 1 1 0
1 0 0 0
1 0 0 0
0 0 0 0
2
V1 V2 V3 V4 V5 V6
0 1 1 0 0 0
1 0 0 1 0 0
1 0 0 0 1 0
0 1 0 0 0 0
0 0 1 0 0 1
0 0 0 0 1 0
1
1 2 3 4 5 6 7 8
0 1 1 0 0 0 0 0
1 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 1 1 0
0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0
0 0 0 1 0 0 0 0
3
以下是代码
#include <iostream>
#include <queue>
using namespace std;
int sum = 0;
class Node
{
public:
int pos;
string data;
Node* next;
Node() { data = "-";pos = 0;next = NULL; }
};
class List
{
public:
Node* head;
List() { head = new Node(); }
void Init(int n);
void Show();
void GetSide(int**mat);
int GetPos(string a);
};
void List::Init(int n)
{
Node* end = head;
for (int i = 1;i <= n;i++)
{
Node* tmp = new Node();
cin >> tmp->data;
tmp->pos = i;
end->next = tmp;
end = end->next;
}
}
void List::Show()
{
Node* end = head->next;
while (end)
{
if (end->next == NULL)
{
cout << end->data;
}
else
{
cout << end->data << " ";
}
end = end->next;
}
cout << endl;
}
void List::GetSide(int**mat)
{
int side;
cin >> side;
for (int i = 0;i < side;i++)
{
string a, b;
cin >> a >> b;
int pos, pos2;
pos = GetPos(a);
pos2 = GetPos(b);
mat[pos-1][pos2-1] = 1;
mat[pos2-1][pos-1] = 1;
}
}
int List::GetPos(string a)
{
Node* end = head->next;
while (end)
{
if (end->data == a)
{
return end->pos;
}
end = end->next;
}
return -1;
}
void BFS(int x,int n,int**mat,int*visit)
{
queue<int>Q;
Q.push(x);
visit[x] = 1;
while (!Q.empty())
{
int cur = Q.front();
Q.pop();
for (int i = 0;i < n;i++)
{
if (visit[i]==0 && mat[cur][i])
{
visit[i] = 1;
Q.push(i);
}
}
}
}
void InitMat(int** mat, int n)
{
for (int i = 0;i < n;i++)
{
for (int j = 0;j < n;j++)
{
mat[j] = new int[n];
mat[i][j] = 0;
}
}
for (int i = 0;i < n;i++)
{
for (int j = 0;j < n;j++)
{
mat[i][j] = 0;
}
}
}
void DeleteMat(int** mat, int n)
{
for (int i = 0;i < n;i++)
{
for (int j = 0;j < n;j++)
{
if (j == n - 1)
{
cout << mat[i][j];
}
else
{
cout << mat[i][j] << " ";
}
}
cout << endl;
}
for (int i = 0;i < n;i++)
{
delete[]mat[i];
}
delete[]mat;
}
int main()
{
int t;
cin >> t;
while (t--)
{
sum = 0;
int n;
cin >> n;
int** mat = new int* [n];
InitMat(mat, n);
List list;
list.Init(n);
list.GetSide(mat);
int* visit = new int[n];
for (int i = 0;i < n;i++)
{
visit[i] = 0;
}
for (int i = 0;i < n;i++)
{
if (visit[i] == 0)
{
BFS(i,n,mat,visit);
sum++;
}
}
list.Show();
DeleteMat(mat, n);
cout << sum << endl;
cout << endl;
delete[]visit;
}
}