构造边双连通分量

Copy from BYVoid
一个有桥的连通图,如何把它通过加边变成边双连通图?方法为首先求出所有的桥,然后删除这些桥边,剩下的每个连通块都是一个双连通子图。把每个双连通子图收缩为一个顶点,再把桥边加回来,最后的这个图一定是一棵树,边连通度为1。

统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf。则至少在树上添加(leaf+1)/2条边,就能使树达到边二连通,所以至少添加的边数就是(leaf+1)/2。具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

A - Road Construction
一个不错的博客

     #include
     #include
     #include
     using namespace std;
     const int MAXN=1010;
     const int MAXE=2010;
     struct Node
     {
         int to,next;
         bool cut;
     };
     Node edge[MAXE];
     int head[MAXN];
     int low[MAXN],dfn[MAXN],onStack[MAXN];
     int cnt,clocks;
     stack sta;
     int belong[MAXN];
     int degree[MAXN];
     int blocks;
     void addEdge(int u,int v)
     {
         edge[cnt].to=v;
         edge[cnt].next=head[u];
         edge[cnt].cut=false;
         head[u]=cnt++;
     }
     void DFS(int u,int fa)
     {
        low[u]=dfn[u]=++clocks;
        onStack[u]=1;
        sta.push(u);
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(v==fa) continue;
            if(dfn[v]==0)
            {
                DFS(v,u);
                low[u]=min(low[u],low[v]);
                if(low[v]>dfn[u])
                {
                    edge[i].cut=true;
                    edge[i^1].cut=true;
                }
            }
            else if(onStack[v]&&dfn[v]

你可能感兴趣的:(构造边双连通分量)