【C++图论】2685. 统计完全连通分量的数量|1769

本文涉及知识点

C++图论

LeetCode2685. 统计完全连通分量的数量

给你一个整数 n 。现有一个包含 n 个顶点的 无向 图,顶点按从 0 到 n - 1 编号。给你一个二维整数数组 edges 其中 edges[i] = [ai, bi] 表示顶点 ai 和 bi 之间存在一条 无向 边。

返回图中 完全连通分量 的数量。

如果在子图中任意两个顶点之间都存在路径,并且子图中没有任何一个顶点与子图外部的顶点共享边,则称其为 连通分量 。

如果连通分量中每对节点之间都存在一条边,则称其为 完全连通分量 。

示例 1:

输入:n = 6, edges = [[0,1],[0,2],[1,2],[3,4]]

输出:3

解释:如上图所示,可以看到此图所有分量都是完全连通分量。

示例 2:

输入:n = 6, edges = [[0,1],[0,2],[1,2],[3,4],[3,5]]

输出:1

解释:包含节点 0、1 和 2 的分量是完全连通分量,因为每对节点之间都存在一条边。

包含节点 3 、4 和 5 的分量不是完全连通分量,因为节点 4 和 5 之间不存在边。

因此,在图中完全连接分量的数量是 1 。

提示:

1 <= n <= 50

0 <= edges.length <= n * (n - 1) / 2

edges[i].length == 2

0 <= ai, bi <= n - 1

ai != bi

不存在重复的边

并集查找

通过并集查找获取各连通分量节点。cnt[cur]记录一个顶点是cur的边的数量。

没有自环,重边的情况下。完全连通分量    ⟺    \iff ⟺ (节点数-1)*节点数等于边数。

代码

核心代码

cpp 复制代码
class CUnionFind
{
public:
	CUnionFind(int iSize) :m_vNodeToRegion(iSize)
	{
		for (int i = 0; i < iSize; i++)
		{
			m_vNodeToRegion[i] = i;
		}
		m_iConnetRegionCount = iSize;
	}	
	CUnionFind(vector<vector<int>>& vNeiBo):CUnionFind(vNeiBo.size())
	{
		for (int i = 0; i < vNeiBo.size(); i++) {
			for (const auto& n : vNeiBo[i]) {
				Union(i, n);
			}
		}
	}
	int GetConnectRegionIndex(int iNode)
	{
		int& iConnectNO = m_vNodeToRegion[iNode];
		if (iNode == iConnectNO)
		{
			return iNode;
		}
		return iConnectNO = GetConnectRegionIndex(iConnectNO);
	}
	void Union(int iNode1, int iNode2)
	{
		const int iConnectNO1 = GetConnectRegionIndex(iNode1);
		const int iConnectNO2 = GetConnectRegionIndex(iNode2);
		if (iConnectNO1 == iConnectNO2)
		{
			return;
		}
		m_iConnetRegionCount--;
		if (iConnectNO1 > iConnectNO2)
		{
			UnionConnect(iConnectNO1, iConnectNO2);
		}
		else
		{
			UnionConnect(iConnectNO2, iConnectNO1);
		}
	}

	bool IsConnect(int iNode1, int iNode2)
	{
		return GetConnectRegionIndex(iNode1) == GetConnectRegionIndex(iNode2);
	}
	int GetConnetRegionCount()const
	{
		return m_iConnetRegionCount;
	}
	vector<int> GetNodeCountOfRegion()//各联通区域的节点数量
	{
		const int iNodeSize = m_vNodeToRegion.size();
		vector<int> vRet(iNodeSize);
		for (int i = 0; i < iNodeSize; i++)
		{
			vRet[GetConnectRegionIndex(i)]++;
		}
		return vRet;
	}
	std::unordered_map<int, vector<int>> GetNodeOfRegion()
	{
		std::unordered_map<int, vector<int>> ret;
		const int iNodeSize = m_vNodeToRegion.size();
		for (int i = 0; i < iNodeSize; i++)
		{
			ret[GetConnectRegionIndex(i)].emplace_back(i);
		}
		return ret;
	}
private:
	void UnionConnect(int iFrom, int iTo)
	{
		m_vNodeToRegion[iFrom] = iTo;
	}
	vector<int> m_vNodeToRegion;//各点所在联通区域的索引,本联通区域任意一点的索引,为了增加可理解性,用最小索引
	int m_iConnetRegionCount;
};
		class Solution {
		public:
			int countCompleteComponents(int n, vector<vector<int>>& edges) {
				CUnionFind uf(n);
				vector<int> cnt(n);
				for (const auto& e : edges) {
					uf.Union(e[0], e[1]);
					cnt[e[0]]++;
					cnt[e[1]]++;
				}
				int ans = 0;
				for (const auto [tmp, v] : uf.GetNodeOfRegion()) {
					int iCnt = 0;
					for (const auto& i : v) {
						iCnt += cnt[i];
					}
					ans += (iCnt == (v.size() - 1) * v.size());
				}
				return ans;
			}
		};

单元测试

cpp 复制代码
int n;
		vector<vector<int>> edges;
		TEST_METHOD(TestMethod11)
		{
			n = 6, edges = { {0,1},{0,2},{1,2},{3,4} };
			auto res = Solution().countCompleteComponents(n, edges);
			AssertEx(3, res);
		}
		TEST_METHOD(TestMethod12)
		{
			n = 6, edges = { {0,1},{0,2},{1,2},{3,4},{3,5} };
			auto res = Solution().countCompleteComponents(n, edges);
			AssertEx(1, res);
		}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。

相关推荐
_周游14 分钟前
【数据结构】_链表经典算法OJ:合并两个有序数组
数据结构·算法·链表
xiao--xin31 分钟前
LeetCode100之子集(78)--Java
java·算法·leetcode·回溯
sjsjs1138 分钟前
【反悔堆】【hard】力扣871. 最低加油次数
算法·leetcode·职场和发展
ke_wu1 小时前
2025牛客寒假算法营3
算法·深度优先·图论
IIIIIIlllii1 小时前
C语言练习(28)
c语言·算法
上海迪士尼351 小时前
parametric_vector = linspace(0, 1, num_points);详细解释
开发语言·算法·matlab
爱是小小的癌1 小时前
Java-数据结构-二叉树习题(3)
java·数据结构·算法
上海迪士尼352 小时前
smooth_path = zeros(num_points, 2);含义
算法·matlab
Victoria.a2 小时前
类与对象(下)
开发语言·c++
自信不孤单2 小时前
Linux多线程
linux·服务器·c++·进程·多线程·线程控制·线程库