1 条题解
-
0
分析:
解题思路
本题的目标是找出给定网络中的 SPF(Single Point of Failure,单点故障)节点,也就是割点。割点是指在一个连通图中,如果删除该节点及其相关的边,图会被分成多个不连通的子图。解题的核心思想是使用 Tarjan 算法来遍历图,通过记录节点的深度优先搜索编号(dfn)和能回溯到的最早祖先节点的编号(low),从而判断哪些节点是割点。
解题原理
核心算法是 Tarjan 算法。Tarjan 算法是一种用于求解图的连通性问题的高效算法,其基于深度优先搜索(DFS)。在 DFS 过程中,对于每个节点,会记录两个重要的信息:
dfn(深度优先搜索编号):节点在 DFS 过程中被访问的顺序编号。 low:节点及其子树能够回溯到的最早祖先节点的 dfn 值。
对于一个节点 v,如果它有一个子节点 u 满足 low[u] >= dfn[v],则说明 v 是割点。因为 low[u] >= dfn[v] 意味着 u 及其子树无法绕过 v 回到 v 的祖先节点,那么删除 v 后,u 及其子树就会与图的其他部分分离。
实现步骤
1.数据输入与图的构建: 不断读取输入的边信息,将边的两个端点存储在邻接表 to 中,同时记录图中最大的节点编号 n。
当输入为 0 时,表示当前网络的输入结束。
2.Tarjan 算法初始化:
初始化 dfn、low、b 和 vis 数组,dfn 用于记录节点的深度优先搜索编号,low 用于记录节点能回溯到的最早祖先节点的编号,b 用于记录每个节点作为割点时产生的子图数量,vis 用于标记节点是否被访问过。
初始化 tot 为 0,作为 dfn 的计数器。
3.Tarjan 算法遍历:
对图中的每个未访问过的节点调用 tarjan 函数进行深度优先搜索。
在 tarjan 函数中,对于当前节点 v,首先标记其为已访问,设置 dfn[v] 和 low[v] 为当前的 tot 值,并将 tot 加 1。
遍历 v 的所有邻接节点 u: 如果 u 未被访问过,递归调用 tarjan(u),然后更新 low[v] 为 low[v] 和 low[u] 中的较小值。如果 low[u] >= dfn[v],则说明 v 是割点,将 b[v] 加 1。
如果 u 已被访问过,更新 low[v] 为 low[v] 和 dfn[u] 中的较小值。
4.处理根节点: 对于深度优先搜索的根节点,需要特殊处理。因为根节点的 b 值初始为其子节点的数量,所以需要将其减 1。
5.输出结果: 遍历所有节点,如果 b[i] >= 1,则说明节点 i 是割点,输出相应信息。
如果没有割点,输出 No SPF nodes。
6.清理工作: 清空邻接表 to,为下一个网络的输入做准备。
C++实现:
#include <iostream> #include <vector> #include <cstring> #include <cstdio> // 添加必要的头文件 #define rep(i, n) for (int i = 0; i < static_cast<int>(n); ++i) // 修改宏定义 using std::cin; using std::cout; using std::max; using std::vector; const int MX = 1005; int dfn[MX], low[MX], tot; int b[MX]; bool vis[MX]; vector<int> to[MX]; inline void chmin(int& x, int y) { if (x > y) x = y; } void tarjan(int v) { vis[v] = true; dfn[v] = low[v] = ++tot; rep(i, to[v].size()) { // 使用修改后的宏定义 int u = to[v][i]; if (!vis[u]) { tarjan(u); chmin(low[v], low[u]); if (low[u] >= dfn[v]) b[v]++; } else { chmin(low[v], dfn[u]); } } } int main() { int cas = 0; while (1) { int n = 0; while (1) { int a; cin >> a; if (!a) break; int b; cin >> b; n = max(n, max(a, b)); --a; --b; to[a].push_back(b); to[b].push_back(a); } if (!n) return 0; if (cas) puts(""); printf("Network #%d\n", ++cas); bool ok = false; memset(vis, false, sizeof vis); memset(b, 0, sizeof b); rep(i, n) { if (!vis[i]) { tarjan(i); b[i]--; } } rep(i, n) { if (b[i] >= 1) { ok = true; printf(" SPF node %d leaves %d subnets\n", i+1, b[i]+1); } } if (!ok) printf(" No SPF nodes\n"); rep(i, n) to[i].clear(); } return 0; }
- 1
信息
- ID
- 524
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 8
- 已通过
- 1
- 上传者