文章目录
Tag
【暴力枚举】【度数】【有向图】【无向图】
题目来源
题目解读
现在有一个无向图,找出连通三元组中度数的最小值,如果没有三元组,则返回 -1
。连通三元组指的是三个节点组成的集合并且两两之间有边。连通三元组的度数指的是排除指向三元组其他顶点的度数。
解题思路
方法一:无向图暴力枚举
看看数据 O ( n 3 ) O(n^3) O(n3) 的时间复杂度不会超时。于是直接枚举所有的三元组,找出最小的度数即可。
具体实现中,需要建立起顶点之间的邻接表 grids
,两个顶点之间相连用 girds[i][j] = 1
表示。需要统计每个节点的度 degree[i]
。
枚举所有顶点时,如果 grids[i][j] = 1
且 grids[j][k] = 1
且 grids[k][i] = 1
时,我们则认为顶点 i
、j
、k
构成连通三元组。该连通三元组的度数为 degree[i] + degree[j] + degree[k] - 6
。
代码
cpp
class Solution {
public:
int minTrioDegree(int n, vector<vector<int>>& edges) {
vector<vector<int>> grids(n, vector<int>(n));
vector<int> degree(n);
for (auto& edge : edges) {
int x = edge[0] - 1, y = edge[1] - 1;
grids[x][y] = grids[y][x] = 1;
++degree[x];
++degree[y];
}
int res = INT_MAX;
for (int i = 0; i < n; ++i) {
for (int j = i+1; j < n; ++j) {
if (grids[i][j] == 1) {
for (int k = j+1; k < n; ++k) {
if (grids[j][k] == 1 && grids[k][i] == 1) {
res = min(res, degree[i] + degree[j] + degree[k] - 6);
}
}
}
}
}
return res == INT_MAX ? -1 : res;
}
};
复杂度分析
时间复杂度: O ( n 3 ) O(n^3) O(n3), n n n 为顶点个数。
空间复杂度: O ( n 2 ) O(n^2) O(n2),因为需要存储顶点之间的关系即邻接矩阵的大小。
方法二:给无向图定向
因为本题的数据规模在 1 0 2 10^2 102 左右,暴力枚举的时间复杂度也在 1 0 7 10^7 107 左右,所以可以过。但是如果数据规模再大一些,比如 1 0 5 10^5 105,那么无向图的暴力枚举一定过不了。对这样规模的数据,如何解决呢?
我们考虑给无向图定向,具体地,如果图中的两个顶点 i
,j
,它们之间有一条无向边:
- 如果
degree[i] < degree[j]
,那么边的方向由i
指向j
; - 如果
degree[i] > degree[j]
,那么边的方向由j
指向i
; - 如果
degree[i] = degree[j]
,那么边的方向由编号较小的顶点指向编号较大的顶点;
我们给无向图进行以上规则的定向之后,任意一个节点的出度都不会超过 2 m \sqrt{2m} 2m , m m m 为图的边数,现在利用反证法进行证明。
假设节点 i
的出度大于 2 m \sqrt{2m} 2m ,那么节点 i
在原始无向图中的度数(出度+入度)大于 2 m \sqrt{2m} 2m ,那么顶点 i
指向的顶点在无向图中的入度大于 2 m \sqrt{2m} 2m ,其出度自然也大于 2 m \sqrt{2m} 2m 。因此总数大于 2 m ∗ 2 m = 2 m \sqrt{2m} * \sqrt{2m} = 2m 2m ∗2m =2m(第一个 2 m \sqrt{2m} 2m 表示从顶点 i
出去的边的数量),这与边数为 m m m 的图总度数为 2 m 2m 2m 矛盾。于是任意一个节点的出度都不会超过 2 m \sqrt{2m} 2m 。
接下来进行有向图上的连通三元组枚举计算就可以了。
实现中除了要使用一个数组 degree
记录各个顶点的度数之外,还会使用到哈希集合 grids
来记录原无向图中与各个顶点连接的所有顶点,使用二维数组 h
记录有向图。
代码
cpp
class Solution {
public:
int minTrioDegree(int n, vector<vector<int>>& edges) {
vector<unordered_set<int>> grids(n); // 原无向图
vector<vector<int>> h(n); // 有向图
vector<int> degree(n); // 统计节点度数
for (auto& edge : edges) {
int x = edge[0] - 1, y = edge[1] - 1;
grids[x].insert(y);
grids[y].insert(x);
++degree[x];
++degree[y];
}
for (auto& edge : edges) {
int x = edge[0] - 1, y = edge[1] - 1;
if (degree[x] < degree[y] || (degree[x] == degree[y] && x < y)) {
h[x].push_back(y);
}
else {
h[y].push_back(x);
}
}
int res = INT_MAX;
for (int i = 0; i < n; ++i) {
for (int j : h[i]) {
for (int k : h[j]) {
if (grids[i].count(k)) {
res = min(res, degree[i] + degree[j] + degree[k] - 6);
}
}
}
}
return res == INT_MAX ? -1 : res;
}
};
复杂度分析
时间复杂度: O ( n + m m ) O(n+m\sqrt{m}) O(n+mm ),因为枚举连通三元组第一层是枚举的是 顶点 i
指向顶点 j
构成的边,这一步部分时间复杂度为 O ( m ) O(m) O(m);第二层枚举 j
指向节点 k
,由于 j
的出度不超过 2 m \sqrt{2m} 2m ,这一部分时间复杂度为 O ( m ) O(\sqrt{m}) O(m );第三层判断 k
是否与 i
构成无向边,使用哈希表,时间复杂度为 O ( 1 ) O(1) O(1)。其中, n n n 为顶点的数量, m m m 为图中的边数。
空间复杂度: O ( m ) O(m) O(m),邻接表使用的空间。
写在最后
以上就是本篇文章的内容了,感谢您的阅读。🍗🍗🍗
如果感到有所收获的话可以给博主点一个 👍 哦。
如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出。💬💬💬