#include using namespace std; const int N = 2e4 + 10, M = 2e5 + 10; //链式前向星 int e[M], h[N], idx, w[M], ne[M]; void add(int a, int b, int c = 0) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } int n, m; // n个顶点,m条边 int dfn[N], low[N], timestamp, root; // tarjan算法 unordered_set s; // 割点集合,自带排序+去重 //割点 void tarjan(int u) { low[u] = dfn[u] = ++timestamp; int son = 0; for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if (!dfn[j]) { son++; tarjan(j); low[u] = min(low[u], low[j]); //根据割点分析,low[j]>= dfn[u]的时候,u是割点 //由于u可能有多个子节点,都会产生回边,u可能进入多次,后面需要去重 if (u != root && low[j] >= dfn[u]) s.insert(u); } low[u] = min(low[u], dfn[j]); } //特例:如果u是根,并且有两个以上的儿子节点,则u为割点 if (u == root && son > 1) s.insert(u); } int main() { scanf("%d %d", &n, &m); memset(h, -1, sizeof h); for (int i = 1; i <= m; i++) { int a, b; scanf("%d %d", &a, &b); add(a, b), add(b, a); } for (root = 1; root <= n; root++) if (!dfn[root]) tarjan(root); //输出割点个数 printf("%d\n", s.size()); //由小到大输出割点 for (auto it = s.begin(); it != s.end(); it++) printf("%d ", *it); //注意这里是 *it,是迭代器的值的意思 return 0; }