Files
python/TangDou/AcWing/SCC/1174.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

80 lines
3.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
const int N = 10010, M = 50010;
int n, m; // n个点,m条边
int d[N]; // 记录一下每个强连通分量的出度
// 链式前向星
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++;
}
// Tarjan算法求强连通分量
int stk[N], top, in_stk[N]; // stk[N]:堆栈,top:配合堆栈使用的游标top,in_stk[N]:是否在栈内
int dfn[N], ts, low[N]; // dfn[N]:时间戳记录数组,ts:时间戳游标, low[N]:从u开始走所能遍历到的最小时间戳
int id[N], scc_cnt, sz[N]; // id[N]:强连通分量块的编号,scc_cnt:强连通分量的编号游标,sz[i]:编号为i的强连通分量中原来点的个数
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]) { // v未访问过
tarjan(v); // dfs深搜
low[u] = min(low[u], low[v]); // 更新low[u]
} else if (in_stk[v]) // v已经栈中,找到强连通分量
low[u] = min(low[u], dfn[v]); // 更新low[u]
}
// 发现强连通分量
if (dfn[u] == low[u]) {
++scc_cnt;
int x;
do {
x = stk[top--];
in_stk[x] = 0;
id[x] = scc_cnt; // 记录x是缩点后编号为ssc_cnt号强连通分量的一员
sz[scc_cnt]++; // 缩点后编号为ssc_cnt号强连通分量中的成员个数+1
} while (x != 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);
}
//(1)求强连通分量,缩点
for (int i = 1; i <= n; i++) // 需示枚举每个点出发尝试,否则会出现有的点没有遍历到的情况
if (!dfn[i]) tarjan(i);
//(2)缩点后其实就是一个DAG,计算出DAG中每个新节点的出度
for (int u = 1; u <= n; u++) // 枚举原图中每个出边,用法好怪异~
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i]; // u->v
int a = id[u], b = id[v]; // u,v分别在哪个强连通分量中
if (a != b) d[a]++; // a号强连通分量,也可以理解为是缩点后的点号,出度++
}
//(3) 出度为0的只能有1个,如果大于1个,就无解,如果正好是一个,返回此强连通分量中结点的个数
int zeros = 0, res = 0;
for (int i = 1; i <= scc_cnt; i++) // 枚举强连通分量块
if (!d[i]) { // 如果出度是0
zeros++; // 出度是0的强连通分量个数+1
res = sz[i]; // 累加此强连通分量中点的个数
if (zeros > 1) { // 如果强连通分量块的数量大于1个,则无解
res = 0;
break;
}
}
//(4)求有多少头牛被除自己之外的所有牛认为是受欢迎的
printf("%d\n", res);
return 0;
}