【模板】割点(割顶)
题目背景
割点
题目描述
给出一个n个点,m条边的无向图,求图的割点。
输入输出格式
输入格式:第一行输入n,m
下面m行每行输入x,y表示x到y有一条边
输出格式:第一行输出割点个数
第二行按照节点编号从小到大输出节点,用空格隔开
输入输出样例
输入样例#1:
6 7 1 2 1 3 1 4 2 5 3 5 4 5 5 6
输出样例#1:
1 5
说明
n,m均为100000
tarjan 图不一定联通!!!
思路
dfs求割点;
在DFS搜索树,我们可以发现有两类节点可以成为割点:
- 对根节点u,若其有两棵或两棵以上的子树,则该根结点u为割点;
- 对非叶子节点u(非根节点),若其子树的节点均没有指向u的祖先节点的回边,说明删除u之后,根结点与u的子树的节点不再连通;则节点u为割点。
2即n->v边中low[v]>=dfn[u];
代码实现
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn=3e5; 5 inline int min_(int x,int y){return x<y?x:y;} 6 int n,m; 7 int a,b; 8 int h[maxn],hs,et[maxn],en[maxn]; 9 void add(int u,int v){ 10 ++hs,et[hs]=v,en[hs]=h[u],h[u]=hs; 11 ++hs,et[hs]=u,en[hs]=h[v],h[v]=hs; 12 } 13 int s[maxn],ss; 14 int dfn[maxn],dfns,low[maxn],v[maxn]; 15 void tarjan(int k,int f){ 16 dfn[k]=low[k]=++dfns; 17 for(int i=h[k];i;i=en[i]) 18 if(et[i]!=f){ 19 if(dfn[et[i]]){ 20 low[k]=min_(low[k],dfn[et[i]]); 21 } 22 else{ 23 tarjan(et[i],k); 24 low[k]=min_(low[k],low[et[i]]); 25 if(low[et[i]]>=dfn[k]) ++v[k]; 26 } 27 } 28 if(f&&v[k]) s[++ss]=k; 29 if(!f&&v[k]>1) s[++ss]=k; 30 } 31 int main(){ 32 scanf("%d%d",&n,&m); 33 for(int i=1;i<=m;i++){ 34 scanf("%d%d",&a,&b); 35 add(a,b); 36 } 37 for(int i=1;i<=n;i++){ 38 if(!dfn[i]){ 39 dfns=0; 40 tarjan(i,0); 41 } 42 } 43 sort(s+1,s+ss+1); 44 printf("%d\n",ss); 45 for(int i=1;i<=ss;i++) printf("%d ",s[i]); 46 putchar('\n'); 47 return 0; 48 }
感谢;
http://www.cnblogs.com/en-heng/p/4002658.html
助我一A;