#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算法 vector v; //割点集合 //割点 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]) v.push_back(u); } low[u] = min(low[u], dfn[j]); } //特例:如果u是根,并且有两个以上的儿子节点,则u为割点 if (u == root && son > 1) v.push_back(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); //排序+去重 sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); //输出割点个数 printf("%d\n", v.size()); //由小到大输出割点 for (int i : v) printf("%d ", i); return 0; }