• POJ


    题目链接:http://poj.org/problem?id=1144

    题目意思:求一个图的割点个数

    割点:在一个无向图中,如果删除一个顶点以及所有相关联的边以后,图的连通分量增多,就称这个点为割点。

     

    1、如果u为树根,那么u有2棵以上子树,则是割点。这种情况容易处理

    2、如果u不为树根,那么(u,v)为树枝边,当Low[v]>=DFN[u]时。解释如下:

    选定一个根节点,从该根节点开始遍历整个图(使用DFS),树上的边一定都是图上的边,称为树边,而图上其余没遍历的边则为非树边(回边)。

    如果一个点不能通过非树边而回到比他树上的父亲的dfs序更小的点,那么如果把它树上的父结点删掉,它就不能通过其他方法与图的其他部分联通,即其父节点为割点。

    void tarjan(int u,int fa)//搜索点u,fa为u的根节点。 
    {
        low[u]=dfn[u]=++tot;
        int son=0;//记录子树个数 
        for(int i=h[u];i!=-1;i=e[i].nxt)
        {
            int v=e[i].v;
            if(!dfn[v])
            {
                tarjan(v,fa);
                low[u]=min(low[u],low[v]);
                if(low[v]>=dfn[u]&&u!=fa)//情况二,v通过回边返回不了比u更早的点。 
                    flag[u]=1;
                if(u==fa)//u是根节点,v这是u的一个子树 
                    son++;
            }
            else
                low[u]=min(low[u],dfn[v]);
        }
        if(son>=2&&u==fa)//情况一,根节点子树>=2 
            flag[u]=1;
    }
    View Code

    dfn[u]表示顶点u第几个被(首次)访问,low[u]表示顶点u及其子树中的点,通过非父子边(回边),能够回溯到的最早的点(dfn最小)的dfn值(但不能通过连接u与其父节点的边)。对于边(u, v),如果low[v]>=dfn[u],此时u就是割点。

     

    但这里也出现一个问题:怎么计算low[u]。

     

    假设当前顶点为u,则默认low[u]=dfn[u],即最早只能回溯到自身。

    有一条边(u, v),如果v未访问过,继续DFS,即通过回边搜索,回溯时 low[u]=min(low[u], low[v]);

    如果v访问过(且u不是v的父亲),就不需要继续DFS了,一定有dfn[v]<dfn[u],low[u]=min(low[u], dfn[v])

    转载自:https://www.cnblogs.com/collectionne/p/6847240.html

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn=150;
    struct node{
        int next,to;
    }edge[maxn*maxn];
    
    int head[maxn],flag[maxn],low[maxn],dfn[maxn];
    int n,m,ans,cnt,tot;
    
    void init()//初始化 
    {
        memset(head,-1,sizeof(head));
        memset(flag,0,sizeof(flag));
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        ans=cnt=tot=0;
    }
    
    void add(int u,int v)//连接两点 
    {
        edge[cnt].to=v;
        edge[cnt].next=head[u];
        head[u]=cnt++;
    }
    
    void tarjan(int u,int fa)//搜索点u,fa为u的根节点。 
    {
        low[u]=dfn[u]=++tot;
        int son=0;//记录子树个数 
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(!dfn[v])
            {
                tarjan(v,fa);
                low[u]=min(low[u],low[v]);
                if(low[v]>=dfn[u]&&u!=fa)//情况二,v通过回边返回不了比u更早的点。 
                    flag[u]=1;
                if(u==fa)//u是根节点,v这是u的一个子树 
                    son++;
            }
            else
                low[u]=min(low[u],dfn[v]);
        }
        if(son>=2&&u==fa)//情况一,根节点子树>=2 
            flag[u]=1;
    }
    
    int main()
    {
        while(~scanf("%d",&n)&&n)
        {
            init();
            while(1)
            {
                int v;
                scanf("%d",&m);
                if(!m)    break;
                while(1)
                {
                    scanf("%d",&v);
                    add(m,v);
                    add(v,m);
                    if(getchar()=='
    ')
                        break;
                }
            }
            tarjan(1,1);
            for(int i=1;i<=n;i++)
                if(flag[i]>0)
                    ans++;
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    I.MX6 RGB clock 和 data 重合
    git 一次删除所有删除的文件
    C# ListView 列宽调整 刷新
    I.MX6 dhcpcd 需要指定网卡
    VS 一些用法设置
    Java写的爬虫的基本程序
    jQuery HighchartsTableHTML表格转Highcharts图表插件
    highcharts 去掉打印和链接
    Highcharts选项配置详细说明文档
    Highcharts使用指南
  • 原文地址:https://www.cnblogs.com/xiongtao/p/9970426.html
Copyright © 2020-2023  润新知