1 条题解

  • 0
    @ 2025-4-17 13:47:08

    分析:

    解题思路

    本题的目标是找出给定网络中的 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
    上传者