poj 3352(边双连通分量)
题目链接:http://poj.org/problem?id=3352
思路:可以求出所有的桥,把桥删掉。然后把所有的连通分支求出来,显然这些连通分支就是原图中的双连通分支。把它们缩成点,然后添上刚才删去的桥,就构成了一棵树。在树上添边使得树变成一个双连通分支即可,这里我们可以直接统计缩点后的叶子节点个数即可,从而要加的边数即为(叶子节点个数+1)/2.
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stack> 6 #include<queue> 7 #include<vector> 8 using namespace std; 9 #define MAXN 2222 10 11 stack<int>S; 12 vector<int>map[MAXN]; 13 14 int low[MAXN],dfn[MAXN]; 15 int color[MAXN]; 16 bool mark[MAXN]; 17 int degree[MAXN]; 18 int n,m,cnt,_count; 19 20 void Tarjan(int u,int father) 21 { 22 low[u]=dfn[u]=++cnt; 23 mark[u]=true; 24 S.push(u); 25 for(int i=0;i<map[u].size();i++){ 26 int v=map[u][i]; 27 if(v==father)continue; 28 if(dfn[v]==0){ 29 Tarjan(v,u); 30 low[u]=min(low[u],low[v]); 31 }else if(mark[v]){ 32 low[u]=min(low[u],dfn[v]); 33 } 34 } 35 if(low[u]==dfn[u]){ 36 int v; 37 _count++; 38 do{ 39 v=S.top(); 40 S.pop(); 41 mark[v]=false; 42 color[v]=_count; 43 }while(u!=v); 44 } 45 } 46 47 int main() 48 { 49 int u,v; 50 while(~scanf("%d%d",&n,&m)){ 51 for(int i=1;i<=n;i++)map[i].clear(); 52 memset(low,0,sizeof(low)); 53 memset(dfn,0,sizeof(dfn)); 54 memset(mark,false,sizeof(mark)); 55 memset(degree,0,sizeof(degree)); 56 memset(color,0,sizeof(color)); 57 cnt=_count=0; 58 while(m--){ 59 scanf("%d%d",&u,&v); 60 map[u].push_back(v); 61 map[v].push_back(u); 62 } 63 for(int i=1;i<=n;i++){ 64 if(dfn[i]==0)Tarjan(i,-1); 65 } 66 for(int i=1;i<=n;i++){ 67 for(int j=0;j<map[i].size();j++){ 68 if(color[i]!=color[map[i][j]]){ 69 degree[color[i]]++; 70 } 71 } 72 } 73 cnt=0; 74 for(int i=1;i<=_count;i++){ 75 if(degree[i]==1)cnt++; 76 } 77 printf("%d\n",(cnt+1)/2); 78 } 79 return 0; 80 } 81 82 83 84 85