知识点-Tarjan
割点:在一个无向连通图中,如果删掉点 x 后图的连通块数量增加,则称点 为图的割点。
条件:
1)对于搜索树上的非根结点 x ,如果存在子节点 i 满足 F[i]>=D[x] ,即 i 向上无法达到 x 的祖先,则 x 为割点,这一点比较能够理解。
2)对于搜索树上的根节点x,若它的子节点数 >=2 ,则 x 为割点。说明 i 必须通过 x 节点到达 x 的祖先,这样去掉 x 后,就能分出两个强连通块。
例题
输入
第一行两个整数,n,m,代表点数及边数。
第2行至m+1行,每行两个整数,a,b,代表边的起点和终点。
输出
从小到大输出割点序号,任意割点序号间用一个空格隔开。
样例输入
6 7 1 4 1 3 4 2 3 2 2 5 2 6 5 6
样例输出
2
提示
n,m<=1000,边使用链式前向星存储。测试数据必含有割点。
代码
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 struct point{ 5 int nxt,to; 6 }edge[1001]; 7 int d[1001],f[1001],head[1001]={0},t[1001],c[1001]; 8 bool bt[1001]; 9 int tol,cnt,n,m,a,b,root,cl; 10 void add(int u,int v) 11 { 12 edge[++cnt].to=v; 13 edge[cnt].nxt=head[u]; 14 head[u]=cnt; 15 } 16 int tarjan(int node,int fa) 17 { 18 d[node]=f[node]=++tol; 19 for(int i=head[node];i!=0;i=edge[i].nxt) 20 { 21 ++t[node]; 22 if(!d[edge[i].to]) 23 { 24 tarjan(edge[i].to,node); 25 f[node]=min(f[node],f[edge[i].to]); 26 if(node==root&&t[node]>=2)bt[node]=1; 27 else if(node!=root&& f[edge[i].to]>=d[node])bt[node]=1; 28 } 29 else if(edge[i].to!=fa)f[node]=min(f[node],d[edge[i].to]); 30 } 31 } 32 int main() 33 { 34 scanf("%d%d",&n,&m); 35 for(int i=1;i<=m;i++) 36 { 37 scanf("%d%d",&a,&b); 38 add(a,b); 39 add(b,a); 40 } 41 root=1; 42 for(int i=1;i<=n;i++)if(!d[i])tarjan(i,root); 43 for(int i=1;i<=n;i++)if(bt[i]) 44 { 45 c[++cl]=i; 46 } 47 for(int i=1;i<cl;i++)printf("%d ",c[i]);printf("%d\n",c[cl]); 48 }
时间: 2024-11-15 22:14:36