You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

87 lines
3.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = N << 1;
int n, m;
int in[N]; // 入度数组
bool flag[N]; // 用于判断所在连通分量是否是目标连通分量是则为1
// 链式前向星
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 stk[N], top; // tarjan算法需要用到的堆栈
bool in_stk[N]; // 是否在栈内
int dfn[N]; // dfs遍历到u的时间
int low[N]; // 从u开始走所能遍历到的最小时间戳
int ts; // 时间戳,dfs序的标识,记录谁先谁后
int id[N], scc_cnt; // 强连通分量块的最新索引号
int sz[N]; // sz[i]表示编号为i的强连通分量中原来点的个数
// tarjan算法求强连通分量
void tarjan(int u) {
dfn[u] = low[u] = ++ts;
stk[++top] = u;
in_stk[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (in_stk[v])
low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
++scc_cnt; // 强连通分量的序号
int x; // 临时变量x,用于枚举栈中当前强连通分量中每个节点
do {
x = stk[top--]; // 弹出节点
in_stk[x] = false; // 标识不在栈中了
id[x] = scc_cnt; // 记录每个节点在哪个强连通分量中
sz[scc_cnt]++; // 这个强连通分量中节点的个数+1
} while (x != u);
}
}
int main() {
memset(h, -1, sizeof h);
scanf("%d %d", &n, &m);
while (m--) {
int a, b;
scanf("%d %d", &a, &b);
add(a, b); // 有向图
}
// Tarjan算法套路
for (int i = 1; i <= n; i++) // 疑问:如果有多个彼此不连通的连通块,那是不是不存在可以到达所有点的点集?
if (!dfn[i]) tarjan(i);
// 枚举所有出边
for (int u = 1; u <= n; u++)
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
int a = id[u], b = id[v]; // u和v不属于同一个强连通分量,且是u ->v
if (a != b) in[b]++; // 则v所在的强连通分量的入度+1
}
// 遍历每个强连通分量找出入度为0的强连通分量
for (int i = 1; i <= scc_cnt; i++)
if (!in[i]) flag[i] = 1;
// 遍历每个节点,如果它所在有强连通分量是入度为零的,则把此点记录到答案数组中,
// 并且修改此强连通分量的入度不是0防止再次被加入到答案数组中
set<int> ans;
for (int i = 1; i <= n; i++) {
int x = id[i];
if (flag[x]) {
ans.insert(i);
flag[x] = 0;
}
}
cout << ans.size() << endl;
for (auto x : ans) cout << x << " ";
return 0;
}