首页 > 代码库 > Tarjan-求割点

Tarjan-求割点

知识点-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 } 

Tarjan-求割点