洛谷 P3388 【模板】割点(割顶)

题目链接

题解

今天复习了一下割点。
关于\(tarjan\)这里不多讲
\(dfn\)\(low\)数组的定义想必大家都知道

仔细观察一下,可以发现
假设便利\(u->v\)这条边
如果 \(low[v] >= dfn[u]\) 就说明\(v\)能到的最小时间戳的点在遍历\(u\)之后,那么\(u\)就是割点

最后特判一下\(tarjan\)第一次的点

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 20010, M = 200010;
struct node {
	int to, next;
}g[M];
int last[N], gl;
inline void add(int x, int y) {
	g[++gl] = (node) {y, last[x]};
	last[x] = gl;
	return ;
}
int dfn[N], low[N], cnt, ans;
bool bj[N], vis[N];
void tarjan(int u, int f) {
	dfn[u] = low[u] = ++cnt;
	vis[u] = 1;
	int son = 0;
	for (int i = last[u]; i; i = g[i].next) {
		int v = g[i].to;
		if (!dfn[v]) {
			tarjan(v, u),low[u] = min(low[u], low[v]);
			if (!f) son++;
			else if (low[v] >= dfn[u] && !bj[u]) bj[u] = 1, ans++;
		}
		else if (vis[v]) low[u] = min(low[u], dfn[v]);
	}
	if (!f && son > 2) ans++, bj[u] = 1;
	return ;
}

int main() {
	int n, m; scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) {
		int x, y; scanf("%d%d", &x, &y);
		add(x, y), add(y, x);
	}
	for (int i = 1; i <= n; i++)
		if (!dfn[i]) tarjan(i, 0);
	cout<<ans<<endl;
	for (int i = 1; i <= n; i++)
		if (bj[i]) printf("%d ", i);
	return 0;
}
posted @ 2018-11-08 17:16  zzy2005  阅读(142)  评论(0编辑  收藏  举报