• UVA 315 Network(无向图求割点)


    题目大意:
    给你一个无向图,求其中割点的个数目。
    输入数据
    第一行一个 n 代表有 n 个点
    接下来有多行,一直到读入一个 0,算整个地图的读入结束,再读入一个0,文件数据结束。
    每行有第一个数字a,代表接下来的数字都 和 a 相连。 
     
    知识汇总:
    割点:无向连通图中,如果删除某点后,图变成不连通了,则称该点为割点。
    这里割点 和 桥 都是无向图里的概念,大家在这里不要混淆了。
     
    求割点
    一个顶点u是割点,当且仅当满足(1)或(2)
    (1) u为树根,且u有多于一个子树。
    (2) u不为树根,且满足存在(u,v)为树枝边(或称 父子边,即u为v在搜索树中的父亲),使得 dfn(u)<=low(v)。(也就是说 V 没办法绕过 u 点到达比 u dfn要小的点)
    注:这里所说的树是指,DFS下的搜索树。
     
    求割点 tarjan里 low  和  dfn
    dfn[u]定义和前面类似,但是low[u]定义为u
    或者u的子树中能够通过非父子边追溯到的
    最早的节点的DFS开始时间
    在Tarjan算法求割点我们要加一个数组 Father[u], 判断两者是否是父子边
     
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    using namespace std;
    #define maxn 10005
    int dfn[maxn];///代表最先遍历到这个点的时间
    int low[maxn];///这个点所能到达之前最早的时间点
    int Father[maxn];///保存这个节点的父亲节点
    int n, m, Time, top;///Time 时间点,  top用于栈操作
    vector<vector<int> > G;
    
    void Init()
    {
        G.clear();
        G.resize(n+1);
        memset(low, 0, sizeof(low));
        memset(dfn, 0, sizeof(dfn));
        memset(Father, 0, sizeof(Father));
        Time = 0;
    }
    
    void Tarjan(int u,int fa)
    {
        low[u] = dfn[u] = ++Time;
        Father[u] = fa;
        int len = G[u].size(), v;
    
        for(int i=0; i<len; i++)
        {
            v = G[u][i];
    
            if(!dfn[v])
            {
                Tarjan(v, u);
                low[u] = min(low[u], low[v]);
            }
            else if(fa != v)///假如我们在这里写上了 low[u] = min(low[v], low[u]),那么就相当于我们由v回了v之前的节点
                low[u] = min(dfn[v], low[u]);
        }
    }
    void solve()
    {/**
    求割点
    一个顶点u是割点,当且仅当满足(1)或(2)
    (1) u为树根,且u有多于一个子树。
    (2) u不为树根,且满足存在(u,v)为树枝边(或称 父子边,即u为v在搜索树中的父亲),使得 dfn(u)<=low(v)。
    (也就是说 V 没办法绕过 u 点到达比 u dfn要小的点)
    注:这里所说的树是指,DFS下的搜索树*/
        int RootSon = 0, ans = 0;///根节点儿子的数量
        bool Cut[maxn] = {false};///标记数组,判断这个点是否是割点
    
        Tarjan(1,0);
    
        for(int i=2; i<=n; i++)
        {
            int v = Father[i];
            if(v == 1)///也是就说 i的父亲是根节点
                RootSon ++;
            else if(dfn[v] <= low[i])
                Cut[v] = true;
        }
    
        for(int i=2; i<=n; i++)
        {
            if(Cut[i])
                ans ++;
        }
        if(RootSon > 1)
            ans++;
    
        printf("%d
    ", ans);
    }
    int main()
    {
        while(scanf("%d", &n), n)
        {
            int a, b;
            char ch;
            Init();
            while(scanf("%d", &a), a)
            {
                while(scanf("%d%c",&b,&ch))
                {
                    G[a].push_back(b);
                    G[b].push_back(a);
                    if(ch == '
    ')
                        break;
                }
            }
            solve();
        }
        return 0;
    }
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    网管的自我修养-网络系统
    网管的自我修养-电脑维护
    iOS继承与类别
    iOS支付宝集成
    HTTP HTTPS TCP/IP UDP
    AFNetworking新版本3.0的迁移
    GCD使用 并行串行队列同步异步执行组合情况
    使用vim遇到的问题
    mac取色
    网络解析
  • 原文地址:https://www.cnblogs.com/chenchengxun/p/4718705.html
Copyright © 2020-2023  润新知