[笔记][题解]割点&lgP3388
[笔记][题解]割点&lgP3388
原题链
割点的概念
在无向连通图中,如果将其中一个点以及所有连接该点的边去掉,图就不再连通,那么这个点就叫做割点.
解题方法
这个题我们用类似于缩点的方法,定义\(dfn\)和\(low\)数组,\(dfn\)指的是\(dfs\)序,\(low[x]\)指的是\(x\)节点不通过父亲节点所能到达的\(dfn\)值最小的点.对于根节点,如果它有两个及以上的子树,那么它就是割点,因为如果没有了根节点,子树与子树之间就不能相连;对于非根节点\(x\),就用\(dfn[x]\)的值和它所有儿子节点的\(low\)值相比,如果存在有\(low[son] ≥ dfn[x]\)则说明\(x\)就是割点,因为\(x\)有某个儿子必须通过它才能到达\(x\)的祖先节点;对于没有儿子的节点,它显然不会是割点.
代码
#include <bits/stdc++.h>
using namespace std;
int n,m;
struct node{
int to,next;
}edge[1000010 * 2];
int fir[1000010],tot,root;
void add(int x, int y){
edge[++tot].to = y;
edge[tot].next = fir[x];
fir[x] = tot;
}
int dfn[1000010],low[1000010],cnt;
bool is[1000010];
void tarjan(int x){
dfn[x] = low[x] = ++cnt;
int flag = 0;
for(int i = fir[x];i;i = edge[i].next){
if(!dfn[edge[i].to]){
tarjan(edge[i].to);
low[x] = min(low[x],low[edge[i].to]);
if(low[edge[i].to] >= dfn[x]){
flag++;
if(flag >= 2 || x != root)
is[x] = 1;
}
}
else low[x] = min(low[x],dfn[edge[i].to]);
}
}
int main(){
cin>>n>>m;
for(int i = 1;i <= m;i++){
int x,y;
cin>>x>>y;
add(x,y);add(y,x);
}
for(int i = 1;i <= n;i++){
if(!dfn[i]){
root = i;
tarjan(i);
}
}
int ans = 0;
for(int i = 1;i <= n;i++)
if(is[i])
ans++;
cout<<ans<<endl;
for(int i = 1;i <= n;i++)
if(is[i])
cout<<i<<" ";
cout<<endl;
return 0;
}