Road Construction POJ - 3352 (边双连通分量)

Road Construction

 POJ - 3352 

题意:一个无向图(无重边),问至少还要加多少边使得去掉任意一条边后任意两点仍可互达。

 无向图的边双连通分量(无重边)

先用一次dfs标记出割边,然后dfs标记出各联通分量

再根据割边,缩点重新建图,生成一颗树

则答案就是(叶子树+1)/2.

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 using namespace std;
 6 const int maxv=1010;
 7 int n,m;
 8 struct Edge{
 9     int v,nex;
10     bool iscut;
11 }e[maxv<<1];
12 int head[maxv];
13 int cnt=0;
14 void init(){
15     memset(head,-1,sizeof(head));
16     cnt=0;
17 }
18 void add(int u,int v){
19     e[cnt].iscut=0;
20     e[cnt].v=v;
21     e[cnt].nex=head[u];
22     head[u]=cnt++;
23 }
24 
25 int pre[maxv],d[maxv],bccno[maxv],dfsk,bcc_cnt;
26 bool vis[maxv];
27 
28 int dfs(int u,int f){
29     int lowu=pre[u]=++dfsk;
30     for(int i=head[u];i!=-1;i=e[i].nex){
31         int v=e[i].v;
32         if(!pre[v]){
33             int lowv=dfs(v,u);
34             lowu=min(lowv,lowu);
35             if(lowv>pre[u]) e[i].iscut=e[i^1].iscut=true;
36         }
37         else if(pre[v]<pre[u]&&v!=f) lowu=min(lowu,pre[v]);  //反向边
38     }
39     return lowu;
40 }
41 void dfs1(int u){
42     vis[u]=1;
43     bccno[u]=bcc_cnt;
44     for(int i=head[u];i!=-1;i=e[i].nex){
45         if(e[i].iscut) continue;
46         if(!vis[e[i].v]) dfs1(e[i].v);
47     }
48 }
49 void find_bcc(int n){
50     memset(pre,0,sizeof(pre));
51     memset(bccno,0,sizeof(bccno));
52     memset(vis,0,sizeof(vis));
53     dfsk=bcc_cnt=0;
54     for(int i=0;i<n;i++) if(!pre[i]) dfs(i,-1);
55     for(int i=0;i<n;i++)
56         if(!vis[i]) bcc_cnt++,dfs1(i);
57 }
58 
59 int main(){
60     while(scanf("%d%d",&n,&m)!=EOF){
61         init();
62         int u,v;
63         for(int i=0;i<m;i++){
64             scanf("%d%d",&u,&v);
65             u--;v--;
66             add(u,v);
67             add(v,u);
68         }
69         find_bcc(n);
70         memset(d,0,sizeof(d));
71         for(int i=0;i<n;i++){
72             for(int j=head[i];j!=-1;j=e[j].nex){
73                 int v=e[j].v;
74                 if(e[j].iscut) d[bccno[v]]++;
75             }
76         }
77         int leaf=0;
78         for(int i=1;i<=bcc_cnt;i++)
79             if(d[i]==1) leaf++;
80         printf("%d\n",(leaf+1)/2);
81     }
82     return 0;
83 }
View Code

 

posted @ 2017-08-18 16:11  yijiull  阅读(284)  评论(0编辑  收藏  举报