分析:无向图求割点。
求割点分两种情况:1,是根并且有超过一个孩子2,不是根,但是对于cur这个点来说,它的某一个孩子不管怎么样一定要经过cur才能到cur之前的点,说明cur是割点,具体操作是引入时间戳,d[i]记录第几个被访问到,low[i]记录在经过不是父亲的点时能到达的最小的d[i]。
注意概念:删除一条边仍然连通=边双连通=不含割边(所以如果flag数组都为0,说明是边双连通)
AC代码
#include <stdio.h> #include <string.h> int s[55][55]; int root; int sum; int flag[15]; int low[15]; int d[15]; int time; int n; int min(int a,int b) { return a<b?a:b; } void dfs(int cur,int father) { int child=0,i; low[cur]=d[cur]=time++; for (i=1;i<=n;i++) { if (s[i][cur]==1) { if (d[i]==0) { child++; dfs(i,cur); low[cur]=min(low[cur],low[i]); if ((cur!=root)&&(low[i]>=d[cur]))//如果i的最低深度大于等于cur的到达时间,说明不管怎么从i到cur之前的总要经过cur,所以cur是割点 { flag[cur]=1; sum++; } if ((cur==root)&&(child==2))//如果cur是根,并且孩子数大于1 { flag[cur]=1; sum++; } } else if (i!=father) low[cur]=min(low[cur],d[i]); } } return; } int main() { int a,b,i,j; freopen("gd.in","r",stdin); freopen("gd.out","w",stdout); scanf("%d",&n); for (i=1;i<=n;i++) for (j=1;j<=n;j++) s[i][j]=0; while(scanf("%d%d",&a,&b)==2) { s[a][b]=1; s[b][a]=1; } root=1; memset(flag,0,sizeof(flag)); memset(d,0,sizeof(d)); sum=0; time=1; dfs(1,root); printf("%d\n",sum); for (i=1;i<=n;i++) if (flag[i]==1) printf("%d\n",i); return 0; }