【题目描述】
给定一个无向图,询问图中存在多少个割点。
【输入描述】
第一行输入两个正整数N、M(N,M <= 50000),表示顶点数目和边数目;
接下来M行,每行输入两个整数A、B,表示顶点A、B之间存在一条双向边。
【输出描述】
输出一个非负整数,表示答案。
【输入样例】
4 4
1 2
2 3
3 4
2 4
【输出样例】
1
源代码: #include<cstdio> #include<algorithm> using namespace std; struct Node { int To,Next; }Edge[100001]; //二倍大。 int m,n,Sum(0),Num(0),Ans(0),i[50001],j[50001],Head[50001]; bool Cut[50001]; void Add(int t1,int t2) //边表。 { Edge[++Sum].To=t2; Edge[Sum].Next=Head[t1]; Head[t1]=Sum; } void Tarjan(int t,int Father) //Tarjan求桥割类。 { int S(0); i[t]=j[t]=++Num; for (int a=Head[t];a;a=Edge[a].Next) { int T=Edge[a].To; if (!j[T]) { S++; Tarjan(T,t); i[t]=min(i[t],i[T]); if (i[T]>=j[t]) //翻不到上方又是直连边,显而易见为割。 Cut[t]=true; //仔细想一下,为什么给Cut[t]赋值而不是Cut[T]。 } else if (T!=Father) i[t]=min(i[t],j[T]); } if (S==1&&!Father) //防止两点的无效重复环。 Cut[t]=false; } int main() //裸Tarjan求割点。 { scanf("%d%d",&n,&m); for (int a=1;a<=m;a++) { int t1,t2; scanf("%d%d",&t1,&t2); Add(t1,t2); Add(t2,t1); } for (int a=1;a<=n;a++) if (!j[a]) Tarjan(a,0); for (int a=1;a<=n;a++) if (Cut[a]) Ans++; printf("%d",Ans); return 0; }