学习的这一篇:https://www.byvoid.com/blog/biconnect
割顶:对于无向图G,如果删除某个点u后,连通分量数目增加,称u为图的关节点或者割顶
u为割顶的条件:
(1)u不为树根,以u的任一子节点为根的子树中没有一个点有返回u的祖先的反向边(返祖边)
(2)u为树根,且u有多于一个子树
紫书上有证明
即为,祖先与每一棵子树之间都有返祖边的话(即,删除u点之后,以v为根的整棵子树都可以通过这条返祖边连回到f),该点不是割顶,如果祖先与它的其中一棵子树缺少返祖边的话,那么这个点就是割顶
实现过程
(1)先链式前向星建图
(2)dfs
(3)定义dfn(u)为u在搜索中遍历到的序号 定义low(u)为u或u的子树能通过非父子边追溯到的最早的节点
low(u)=min{dfn(u),
dfn(v)//(u,v)为返祖边,等价于dfn(v)<dfn(u),且v不是u的父亲节点
low(v)//(u,v)为树枝边(父子边)}
(4)当dfn(u)<=low(v)的时候,u为割顶
代码学习的这一篇
http://www.cnblogs.com/naturepengchen/articles/4053890.html
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath> 5 #include<stack> 6 #include<vector> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<algorithm> 11 using namespace std; 12 13 #define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i) 14 15 typedef long long LL; 16 const int INF = (1<<30)-1; 17 const int mod=1000000007; 18 const int maxn=100005; 19 20 int first[maxn],next[maxn],ver[maxn]; 21 int ecnt,tot; 22 int low[maxn],iscut[maxn],dfn[maxn]; 23 24 void dfs(int p,int pre){ 25 low[p]=dfn[p]=++tot; 26 int son=0; 27 28 for(int i=first[p];i!=-1;i=next[i]){ 29 int v=ver[i]; 30 if(!dfn[v]){ 31 ++son; 32 dfs(v,p); 33 low[p]=min(low[p],low[v]); 34 if(low[v]>=dfn[p]) iscut[p]=1; 35 } 36 37 else if(dfn[v]<dfn[p]&&v!=pre) {//用返祖边更新low函数 38 low[p]=min(low[p],dfn[v]); 39 } 40 } 41 if(pre<0&&son==1) iscut[p]=0; 42 } 43 44 void addedges(int u,int v){ 45 next[++ecnt]=first[u]; 46 ver[ecnt]=v; 47 first[u]=ecnt; 48 } 49 50 void init(){ 51 memset(low,0,sizeof(low)); 52 memset(dfn,0,sizeof(dfn)); 53 memset(iscut,0,sizeof(iscut)); 54 memset(first,-1,sizeof(first)); 55 56 ecnt=0;tot=0; 57 } 58 59 int main(){ 60 int a,b,n; 61 char c; 62 while(scanf("%d",&n)!=EOF&&n){ 63 init(); 64 while(scanf("%d",&a)!=EOF&&a){ 65 while(scanf("%d%c",&b,&c)!=EOF){ 66 addedges(a,b); 67 addedges(b,a); 68 if(c=='\n') break; 69 } 70 } 71 dfs(1,-1); 72 int ans=0; 73 for(int i=1;i<=n;i++) 74 ans+=iscut[i]; 75 76 printf("%d\n",ans); 77 } 78 return 0; 79 }