RevolC FaeLoN UVA

来源:互联网 发布:经纬度定位软件ios 编辑:程序博客网 时间:2024/06/05 17:20

RevolC FaeLoN UVA - 10972

图论·边-双连通分量

http://blog.csdn.net/l123012013048/article/details/47373065

题目大意:

把无向图的每一条边变成一条有向边,形成一个并加入最少的有向边,让新图称为一个强连通分量。问最小加边数。

题解:

求出所有的边-双连通分量,把他们缩点,得到多棵无根树森林。
树上的点是边-双连通分量,边是桥。

对于一个连通块,如果它的节点个数>1:

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

另外,两个连通块的互相连接并不需要额外的边。
只要把给他们加的边各自拆开一条,就能把他们连起来连到一起。

对于一个孤立的点,它需要一条边:

如果有n个点,要求在这n个点间添加有向边,使得这n个点变成强连通,那么需要添加的边的数量为n,均摊每个点一条。

有了上面这个结论,求的时候就比较好办了,处理的时候,只需要统计出所有度为1和度为0的缩点的数量即可 。
假设度为1的数量为A (叶子结点,连通图里面的)
度为2的数量为B(孤立的点)
那么所需要连的边就是(A + 1) / 2 + B

注意求边-双连通分量的时候,不能把当前u取出来,而是只取到v。
在dfs外面要把栈里剩下的元素作为一个新的双联通分量。

Code:

#include <iostream>#include <cstdio>#include <cstring>#include <stack>#include <vector>#define MP make_pair#define D(x) cout<<#x<<" = "<<x<<"  "#define E cout<<endlusing namespace std;typedef pair<int,int> pii;const int N = 2017;const int M = 20017;int n,m;struct Edge{    int u,v,next;}e[M];int head[N], ec=0;void clear(){ memset(head,0,sizeof(head)); ec=0; }void add(int a,int b){    ec++; e[ec].u=a; e[ec].v=b; e[ec].next=head[a]; head[a]=ec;}int belong[N],bridge[M][2],low[N],dfn[N],du[N],tim,bcc_cnt,bridge_cnt;stack<int> s; void dfs(int u,int pa){    low[u]=dfn[u]=++tim;    s.push(u);    for(int i=head[u];i;i=e[i].next){        int v=e[i].v;        if(!dfn[v]){            dfs(v,u);            low[u]=min(low[u],low[v]);            if(low[v]>dfn[u]){                bridge_cnt++;                bridge[bridge_cnt][0]=u; bridge[bridge_cnt][1]=v;                bcc_cnt++;                while(true){                    int x=s.top(); s.pop();                    belong[x]=bcc_cnt;                    if(x==v) break;                }            }        }        else if(dfn[v]<dfn[u] && v!=pa){            low[u]=min(low[u],dfn[v]);        }     }}void find_bcc(){    bcc_cnt=0; tim=0; bridge_cnt=0;    memset(dfn,0,sizeof(dfn));    memset(belong,0,sizeof(belong));    for(int i=1;i<=n;i++){        if(!dfn[i]){            dfs(i,-1);            bcc_cnt++;            while(!s.empty()){                int x=s.top(); s.pop();                belong[x]=bcc_cnt;            }        }    }}int main(){    freopen("a.in","r",stdin);    while(~scanf("%d%d",&n,&m) && (n||m)){        clear();        int a,b;        for(int i=1;i<=m;i++){            scanf("%d%d",&a,&b);            add(a,b); add(b,a);        }        find_bcc();//      D(bcc_cnt); E;//      for(int i=1;i<=n;i++){//          D(belong[i]);//      } E;        if(bcc_cnt==1){            printf("0\n");            continue;        }        memset(du,0,sizeof(du));        for(int i=1;i<=bridge_cnt;i++){            du[belong[bridge[i][0]]]++;             du[belong[bridge[i][1]]]++;        }//      for(int i=1;i<=bcc_cnt;i++) D(du[i]); E;        int A=0,B=0;        for(int i=1;i<=bcc_cnt;i++){            if(du[i]==1) A++;            if(du[i]==0) B++;        }//      D(ans); E;        printf("%d\n",(A+1)/2+B);    }} 
原创粉丝点击