zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    springmvc
    POJ 3683 Priest John's Busiest Day
    POJ 3678 Katu Puzzle
    HDU 1815 Building roads
    CDOJ UESTC 1220 The Battle of Guandu
    HDU 3715 Go Deeper
    HDU 3622 Bomb Game
    POJ 3207 Ikki's Story IV
    POJ 3648 Wedding
    HDU 1814 Peaceful Commission
  • 原文地址:https://www.cnblogs.com/xiongtao/p/9970426.html
Copyright © 2011-2022 走看看