[笔记][题解]割点&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;
}
posted @ 2020-10-30 16:02  czyczy  阅读(130)  评论(0编辑  收藏  举报