边双连通分量 jarjan (poj 3177)
大意:给定一个无向连通图,判断至少加多少的边,才能使任意两点之间至少有两条的独立的路(没有公共的边,但可以经过同一个中间的顶点)。
思路:在同一个双连通分量里的所有的点可以看做一个点,收缩后,新图是一棵树,树的边便是原图的桥。现在问题转化为“在树中至少添加多少条边能使图变成边双连通图”,即添加的边的个数=(树中度为一的节点数目+1)/2,用trajan算法求双联通分量
这是一个模板
1 #include<iostream> 2 #include<cstdio> 3 #include<string.h> 4 #include<algorithm> 5 #include<queue> 6 #include<vector> 7 using namespace std; 8 const int maxn=1e4+10; 9 struct node 10 { 11 int v,cut,nxt; 12 }G[2*maxn]; 13 int cnt; 14 int head[maxn]; 15 int Stack[maxn]; 16 int instack[maxn]; 17 int low[maxn],dfn[maxn]; 18 int belong[maxn],du[maxn]; 19 int block,index; 20 int bridge,top; 21 void init() 22 { 23 cnt=0; 24 memset(head,-1,sizeof(head)); 25 } 26 void build(int u,int v) 27 { 28 G[cnt].v=v;G[cnt].nxt=head[u];G[cnt].cut=0;head[u]=cnt++; 29 } 30 void tarjan(int u,int pre) 31 { 32 low[u]=dfn[u]=++index; 33 Stack[top++]=u; 34 instack[u]=1; 35 int v; 36 for(int i=head[u];i!=-1;i=G[i].nxt){ 37 v=G[i].v; 38 if(pre==v) continue; 39 if(!dfn[v]){ 40 tarjan(v,u); 41 low[u]=min(low[u],low[v]); 42 if(low[v]>dfn[u]){ 43 bridge++; 44 G[i].cut=1; 45 G[i^1].cut=1; 46 } 47 } 48 else if(low[u]>dfn[v]&&instack[v]) low[u]=dfn[v]; 49 } 50 if(low[u]==dfn[u]){ 51 block++; 52 do{ 53 v=Stack[--top]; 54 instack[v]=0; 55 belong[v]=block; 56 }while(v!=u); 57 } 58 } 59 void solve(int n) 60 { 61 int i,j; 62 int index=0; 63 bridge=0; 64 top=0; 65 block=0; 66 memset(low,0,sizeof(low)); 67 memset(dfn,0,sizeof(dfn)); 68 memset(belong,0,sizeof(belong)); 69 memset(instack,0,sizeof(instack)); 70 tarjan(1,0); 71 for(i=1;i<=n;i++){ 72 for(j=1;j!=-1;j=G[j].nxt){ 73 if(G[j].cut) 74 du[belong[i]]++; 75 } 76 } 77 int ans=0; 78 for(i=1;i<=block;i++){ 79 if(du[i]==1) 80 ans++; 81 } 82 printf("%d\n",(ans+1)/2); 83 } 84 int main() 85 { 86 int n,m; 87 while(~scanf("%d%d",&n,&m)){ 88 init(); 89 for(int i=0;i<m;i++){ 90 int u,v; 91 scanf("%d%d",&u,&v); 92 build(u,v); 93 build(v,u); 94 } 95 solve(n); 96 } 97 return 0; 98 }