C++通过邻接矩阵求连通分量(BFS)

  在求图的连通分量时可能会碰见的问题--已经构造出了邻接矩阵,但不知道怎么求连通分量。这里选择用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;
	}
}

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值