[Poj]3177——双联通分量

[题目大意]
  • 给定一张图,求最少加入几条边可以使得整个图成为一个边双连通图。

[分析题解]
  •  经典的老题目了,学双联通分量必做。前一段时间做了一次,结果不断的WA-_-一怒之下扔掉,今天又回来做,详细的修改了程序框架之后重写很快就过了。
  • 具体的说也是非常简单:求双联通分量,染色,缩点,然后求度为1的点数,答案就是(这个数+1) Div 2。
  • 因为有重边,以前不太明确怎么处理,直到看了Guo神牛的题解之后,恍然大悟,只需要在Dfs的同时,记下到这个边的这条边的反向边的编号,到时候不要再从这个走回去,但是可以从重边走回去。限制边,而不是限制点,这样处理就搞定了重边的情况。
  • 其他的就比较简单了,按照Low和Dfn的定义,如果某个点拓展完后Low=Dfn,那么栈中从栈顶到这个店为止的部分都属于同一个双联通分量。这个由Dfs树的性质决定的。这样求出来之后,只需要对这些点进行染色,不需要真的缩点,只要再去重新枚举原图中的边,向新的颜色不同的顶点之间加边即可。又由于双联通分量的定义,这样新的图一定是一个树,如果不是一个树,那有环的部分按照定义是应该在同一个双联通分量中的。然后求求度数,计算输出即可。

[个人代码]

fayaa.com/code/view/26770/


[相关链接] 
  1. http://www.byvoid.com/blog/biconnect/zh-hans/
  2. http://www.byvoid.com/blog/pku-3177/ 
  3. http://www.cnblogs.com/ACystalMoon/articles/2381205.html

  4.  

    http://www.cnblogs.com/rainydays/archive/2011/07/06/2099524.html

     


[启发总结]
  1.  特别是第四个!以前我了解了Low的定义,但是却没有发现这个区别:我们平时使用的Low,都是其子孙通过一条返祖边直接到达的点来决定的。如果我们把这个限制取消掉,按照其提供的做法,可以很简单的对双联通分量进行染色。
    ExpandedBlockStart.gif http://www.cnblogs.com/rainydays/archive/2011/07/06/2099524.html
    poj3177

    求添加多少条边可变连通图。
    接着poj3352的看。对于这种题,我们正常的做法是求桥,删桥,求连通分支,缩点,构建新图,求叶子数。
    我们有一种简便方法。需要对tarjan算法做一些变化。我们之前规定low[u]是其子孙通过一条返祖边直接到达的点,把这个改成是其子孙可以连续通过多条返祖边所能到达的点。那么low[u]=min(low[v],dfn[u]);
    这样做的缺陷是,不能求割点了,多次返祖会导致求割点的错误,在多环两两以单个点相连排成一条线,且每两个连接点间只有一条边的情况中,那些连接点本应是割点,但是在dfs过程中,这些连接点之间的边又恰好不是树枝边的话,low[u]可能会通过多次返祖,从一个割点不断的经过这些割点到达最上边的割点才记录下low[u]。
    这样中间的割点就都不符合dfn(u)<=low[v]了。
    但是这样做有一个好处,就是所有的对于边的双连通分支都以low标记出来了,即属于同一双连通分支的所有点的low都等于同一个值。因为在不遇到桥的情况下,low可以返祖到该连同分支在遍历树中的最高点(dfn最小的点)。
    这样就相当于整理出了所有的对于边的双连通分支。我们直接遍历所有的边,观察边的两端点是否属于同一分支,若不属于则修改两点的度数。然后看有多少个度数为1的点即可。
    这题有重边,注意判断。
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    using  namespace std;

    #define maxn 5005
    #define maxm 10005

    struct Edge
    {
         int v, next;
    } edge[maxm];

    int n, m;
    int head[maxn];
    bool hash[maxn][maxn];
    int ecount, tcount;
    int dfn[maxn], vis[maxn], low[maxn], degree[maxn];

    void addedge( int a,  int b)
    {
        edge[ecount].v = b;
        edge[ecount].next = head[a];
        head[a] = ecount;
        hash[a][b] = hash[b][a] =  true;
        ecount++;
    }

    void input()
    {
        memset(head, - 1sizeof(head));
        ecount =  0;
        scanf( " %d%d ", &n, &m);
         for ( int i =  0; i < m; i++)
        {
             int a, b;
            scanf( " %d%d ", &a, &b);
            a--;
            b--;
             if (hash[a][b])
                 continue;
            addedge(a, b);
            addedge(b, a);
        }
    }

    void dfs( int fa,  int u)
    {
        vis[u] =  true;
        low[u] = dfn[u] = tcount++;
         for ( int i = head[u]; i != - 1; i = edge[i].next)
        {
             int v = edge[i].v;
             if (v == fa)
                 continue;
             if (!vis[v])
                dfs(u, v);
            low[u] = min(low[u], low[v]);
        }
    }

    int tarjan()
    {
        memset(dfn,  0sizeof(dfn));
        memset(vis,  0sizeof(vis));
        memset(degree,  0sizeof(degree));
        tcount =  0;
        dfs( 00);
         int ret =  0;
         for ( int i =  0; i < n; i++)
             for ( int j = head[i]; j != - 1; j = edge[j].next)
            {
                 int v = edge[j].v;
                 if (low[i] != low[v])
                    degree[low[i]]++;
            }
         for ( int i =  0; i < n; i++)
             if (degree[i] ==  1)
                ret++;
         return (ret +  1) /  2;
    }

    int main()
    {
         // freopen("t.txt", "r", stdin);
        input();
         int ans = tarjan();
        printf( " %d\n ", ans);
         return  0;
    }

转载于:https://www.cnblogs.com/perseawe/archive/2012/06/07/Poj3711.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值