关于这题统计答案的疑问
查看原帖
关于这题统计答案的疑问
533544
WillHou楼主2024/10/24 11:15

这是本题用 Tarjan 的 AC 代码:

#include <iostream>
#include <vector>
#include <stack>
const int N = 1e5 + 9;
int n, m;
int dfn[N], low[N], time_stamp;
int scc[N], sz[N], scc_cnt;
bool instk[N];
int deg[N];
std::stack<int> stk;
std::vector<int> adj[N];
void tarjan(int u) {
	dfn[u] = low[u] = ++time_stamp;
	stk.emplace(u), instk[u] = true;
	for (auto v : adj[u]) {
		if (!dfn[v]) {
			tarjan(v);
			low[u] = std::min(low[u], low[v]);
		} else if (instk[v]) {
			low[u] = std::min(low[u], dfn[v]);
		}
	}
	if (low[u] == dfn[u]) {
		scc_cnt++;
		int v;
		// printf("SCC #%d: ", scc_cnt);
		do {
			v = stk.top(); stk.pop();
			instk[v] = false;
			scc[v] = scc_cnt;
			sz[scc_cnt]++;
			// printf("%d ", v);
		} while (v != u);
		// puts("");
	}
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) {
		int u, v;
		scanf("%d%d", &u, &v);
		adj[u].emplace_back(v);
	}
	for (int i = 1; i <= n; i++) {
		if (!dfn[i]) tarjan(i);
	}
	for (int u = 1; u <= n; u++) {
		for (auto v : adj[u]) {
			int sccu = scc[u], sccv = scc[v];
			if (sccu != sccv) {
				deg[scc[u]]++;
			}
		}
	}
	int ans = 0;
	for (int i = 1; i <= scc_cnt; i++) {
		if (deg[i] == 0 and ans) {
			puts("0");
			return 0;
		} else if (deg[i] == 0) {
			ans = sz[i];
		}
	}
	printf("%d\n", ans);
	return 0;
}

既然强连通分量编号的倒序就是缩点后的拓扑排序,那么为什么不可以在统计答案的时候判断一旦 deg[i] > 0 就立刻跳出循环?将源代码 5656 行到 6363 行的 for 循环替换成如下代码是错误的。

for (int i = 1; i <= scc_cnt; i++) {
  	if (deg[i]) break;
  	if (deg[i] == 0 and ans) {
		puts("0");
		return 0;
 	}
 	ans = sz[i];
}
2024/10/24 11:15
加载中...