您的位置:首页 > 其它

poj 3352 Road Construction (无向图edge-BCC缩点)

2015-06-27 19:45 295 查看
题目大意:无向简单图,添加尽量少的边使得图为边-双连通。输出最少需要添加的边条数。

这儿有个结论:对于一棵树,至少添加(其叶子节点+1)/2条边,便可得到一个边-双连通图。在网上找了很久,没有找到严格的证明。不过可以这样理解:对于一棵树,首先可以找到它的直径(或者公共祖先最远的两个叶子节点),对于直径两端的叶子节点连一条边,这样可以尽可能多地使得桥数目减少。然后再找剩下的叶子节点中公共祖先最远的两个,再连一条边,依次下去。得到的结果就是那样。

根据这个结论就比较容易想到解法了:先进行BCC缩点,转换为一颗树,然后统计该树中度数为1的节点个数(叶子节点),根据结论便可得到答案。

求BCC的写法与SCC的写法大致一样,只是加了个参数,防止对一条无向边访问两次。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
#define N 200005
struct Edge{
    int to,next;
    bool flag;
}edge[2000005];

int dfn
,low
,bccno
,head
,bridge_num,cnt,dfs_clock,bcc_cnt;
stack<int> S;

void add(int u,int v){
    edge[cnt].flag=0;
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}

void dfs(int u,int fa){
    dfn[u]=low[u]=++dfs_clock;
    S.push(u);
    for(int i=head[u];~i;i=edge[i].next){
        int v=edge[i].to;
        if(v==fa) continue; //保证由一条无向边拆成的两条有向边只访问一条
        if(!dfn[v]){
            dfs(v,u);
            low[u]=min(low[u],low[v]);//用后代的low函数更新自身
            if(low[v]>dfn[u]){
                ++bridge_num;
                edge[i].flag=edge[i^1].flag=1;
            }
        }
        else if(!bccno[v]){
            low[u]=min(low[u],dfn[v]);//用反向边更新
        }
    }
    if(low[u]==dfn[u]){
        ++bcc_cnt;
        for(;;){
            int x=S.top();S.pop();
            bccno[x]=bcc_cnt;
            if(x==u) break;
        }
    }
}

void find_bcc(int n){
    dfs_clock=bcc_cnt=bridge_num=0;
    memset(bccno,0,sizeof(bccno));
    memset(dfn,0,sizeof(dfn));
    for(int i=0;i<n;++i) if(!dfn[i]) dfs(i,-1);
}

int deg
;
int main()
{
    int n,m,i,j,x,y;
    while(~scanf("%d%d",&n,&m))
    {
        memset(head,-1,sizeof(head));
        memset(deg,0,sizeof(deg));
        cnt=0;
        for(i=0;i<m;++i){
            scanf("%d%d",&x,&y);
            add(--x,--y);
            add(y,x);
        }
        find_bcc(n);
        for(i=0;i<n;++i){
            for(j=head[i];~j;j=edge[j].next){
                if(edge[j].flag) deg[bccno[i]]++;
            }
        }
        int ans=0;
        for(i=1;i<=bcc_cnt;++i) if(deg[i]==1) ++ans;
        printf("%d\n",(ans+1)/2);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: