📅  最后修改于: 2023-12-03 15:12:46.098000             🧑  作者: Mango
本题为门 | 门 CS 1999第43题,属于数据结构与算法分类,难度为中等。
有一个 $n$ 个点 $m$ 条边的有向图,边权均为正整数。定义点 $i$ 的度数为该点的入度与出度之和,求度数最小的点,若有多个,输出点标号最小的那个。
4 5
1 2 2
1 3 5
2 3 1
3 1 2
3 4 5
3
本题需要求解的是度数最小的点,因此我们需要统计每个点的度数,并求出最小的度数。
不难想到,对于每个点,我们可以分别计算它的入度和出度,最后将两者之和求出即可得到该点的度数。
统计出度简单,只需使用邻接表存储图,遍历每个节点的出边即可。统计入度相对比较麻烦,需要对每个节点的所有出边进行遍历,找出对应的终点节点,并统计其入度。
在求完每个点的度数后,只需遍历所有点并找出最小度数即可,注意输出标号最小的那个。
实现上述思路,我们可以先定义一个用于存储邻接表的结构体,并封装辅助函数来进行入度和度数的计算。最终算法的伪代码如下:
struct Node {
int v, w;
Node *next;
};
// 存储邻接表的结构体
struct Graph {
int n, m;
Node *heads; // 存储每个节点的邻接表头
};
// 辅助函数:计算指定节点的出度
int out_deg(Graph &g, int v) {
int ans = 0;
for (Node *p = g.heads[v].next; p != nullptr; p = p->next)
ans++;
return ans;
}
// 辅助函数:计算指定节点的入度
int in_deg(Graph &g, int v) {
int ans = 0;
for (int u = 1; u <= g.n; u++) {
for (Node *p = g.heads[u].next; p != nullptr; p = p->next) {
if (p->v == v) {
ans++;
break;
}
}
}
return ans;
}
// 主函数
int main() {
Graph g;
// 读入图,初始化邻接表等
for (int i = 1; i <= g.n; i++) {
int d = in_deg(g, i) + out_deg(g, i);
if (d < min_deg) {
ans = i;
min_deg = d;
} else if (d == min_deg && i < ans) {
ans = i;
}
}
// 输出结果
printf("%d", ans);
return 0;
}
算法的时间复杂度为 $O(n^3)$,虽然在本题数据范围下可以通过,但仍有优化的空间。例如,我们可以使用邻接表和邻接矩阵结合的方式来进行入度的统计,从而将时间复杂度降为 $O(n^2)$。此外,我们也可以使用拓扑排序(BFS)来统计度数,进一步将时间复杂度降为 $O(n+m)$。
答:我们可以先使用 BFS 遍历指定点所在的连通块,并记录每个点到指定点的距离。然后再遍历整张图,只考虑合法的点,即和指定点同处一个连通块的点,统计这些点的度数。在统计完度数之后,遍历所有度数最小的点,找到其中离指定点最近的点即可。
答:我们可以使用 C++11 的智能指针技术,将邻接表中的节点存储为 std::unique_ptr<Node>
类型,从而避免了手动释放内存的麻烦。
本题主要考察对于有向图的建模及基础算法的掌握,例如邻接表的使用、度数的计算等。对于初学者而言,建议先学习邻接表、BFS 等基础算法,再考虑更高级的优化和扩展。在实际编码时,还需要注意细节,例如输出最小度数的那个节点时,需要按照题目要求返回标号最小的那个。