Road Construction POJ - 3352 (边双连通分量)
Road Construction
题意:一个无向图(无重边),问至少还要加多少边使得去掉任意一条边后任意两点仍可互达。
无向图的边双连通分量(无重边)
先用一次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 }