zoukankan      html  css  js  c++  java
  • 连通图/割点、割边

    先了解一下每个名词的含义

    无向图:没有方向的图
    无向连通图:图中任意两节点可互相到达的无向图
    无向非连通图:不是无向连通图
    无相连通分量:无向非连通图中的最大连通子图
    割点:删掉这个点就不连通
    割边:删掉这个边就不连通
    强联通有向图:任意两点可以到达的有向图
    弱连通有向图:如果忽略边的方向是一个无向连通图
    强联通分量(SCC):非强连通图的极大连通子图

    对于求无向图中的割点和割边

    为什么有割点和非割点之分,那就是由于无向图连通有环,环中的点自然不是割点,如果无向连通图要是树的话,那么所有点就都是割点了

    对于Tarjan算法,则是选择一个为根节点进行dfs搜索,用dfn数组存储每个节点出现时间(时间从1开始,0代表没搜过)

    如果该图中有环那么该环中一定有first(最早出现的节点)和last(最晚出现的节点),而且last与fisrt有边能直接相连,当last搜寻下一个节点时便会搜到first

    这时需要一个low数组存储每个点能搜索到的最早出现的时间,只有对于环中last搜到fisrt时,low数组能变小,而且会让从fisrt->last这条树链上的所有点i,使得low[i]=min(low[i],dfn[first])(代码中应该是low[u]=min(low[u],low[v]))

    搜完所有点以后

    若求割点每个点可以分为根节点和不是根节点

    对于根节点,若有两个子节点那么该点即是割点(对于如何判断有几个子节点,在搜索时用一个fa[]数组存好由谁转移过来的,最后以判断有几个是由根节点转换的即可)

    对于不是根节点i,若low[i]>=dfn[fa[i]]则该点父亲是割点(因为该点不通过该点与父亲的边最多只能搜到父亲节,那么删掉父亲节点,该点则不能搜到父亲以上节点)

    若求割边,只需要搜每个不是根节点的点i,若low[i]>dfn[fa[i]]那么该点与父亲连的边为割边(因为若该点所能搜到的最早出现的点也比父亲出现的晚,说明该点不能搜到父亲上面的点)

    代码如下

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<vector>
    using namespace std;
    int dfn[1005],low[1005],fa[1005];
    bool vis[1005];
    vector<int>G[1005];
    int cnt;
    void tarjan(int u)
    {
        dfn[u]=low[u]=++cnt;
        int i,j;
        for(i=0; i<G[u].size(); i++)
        {
            int v=G[u][i];
            if(dfn[v]==0)
            {
                fa[v]=u;
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else
                low[u]=min(low[u],dfn[v]);
        }
    }
    int gedian(int n)
    {
        int num=0;
        memset(vis,false,sizeof(vis));
        int i,j,fu;
        for(i=2; i<=n; i++)
        {
            fu=fa[i];
            if(fu==1)
                num++;
            else
            {
                if(low[i]>=dfn[fu])
                    vis[fu]=true;
            }
        }
        if(num>=2)
            vis[1]=true;
        int sum=0;
        for(i=1; i<=n; i++)
        {
            if(vis[i])
                sum++;
        }
        return sum;
    }
    int gebian(int n)
    {
        int i,j,sum=0,fu;
        for(i=1;i<=n;i++)
        {
            fu=fa[i];
            if(fu>0&&low[i]>dfn[fu])
                sum++;
        }
        return sum;
    }
    int main()
    {
        int n,m;
        while(scanf("%d %d",&n,&m)!=EOF)
        {
            int i,j;
            for(i=1; i<=n; i++)
                G[i].clear();
            int x,y;
            for(i=0; i<m; i++)
            {
                scanf("%d %d",&x,&y);
                G[x].push_back(y);
                G[y].push_back(x);
            }
            memset(dfn,0,sizeof(dfn));
            cnt=0;
            memset(fa,0,sizeof(fa));
            tarjan(1);

        }
    }
    跑一遍taijan以后有向图变成一棵树,对于原图环中一定被舍掉,但恰恰由于这条边改变了low值,因为树都是从上指向下,只有这条边往上指了,使得
    该边下边点low值可以变成上边点dfn值
    求割点
    对于根如果有两棵子树则该点是割点
    否则若该点u存在一个子节点v使得 low[v]>=dfn[u]则u为割点
    求割边
    对于某条边的子节点v父节点u存在 low[v]>dfn[u]则该边为割边

  • 相关阅读:
    Jemter---基础概念
    Jmeter---线程操作
    性能接口面试题
    Linux---网络命令
    测试所用链接地址
    Linux---压缩解压命令
    Linux----用户管理命令
    性能面试题
    Linux---帮助命令
    Linux--文件搜索命令
  • 原文地址:https://www.cnblogs.com/lmhyhblog/p/8950549.html
Copyright © 2011-2022 走看看