2 条题解
-
1
2772. 环
简要题意
个节点 条边的有向图,求有多少个节点 满足 存在一个包含 在内的环,环长对 取模时
思路
看到了 有向图、环、,就可以联想到强联通分量。
考虑对每一个强联通分量依次处理,很显然,不可能有一个环跨过强连通分量,所以这样不会少算可能性。
强连通分量的定义是:满足任意两个节点可以互相到达的极大子图。
所以一个强联通分量中,只要一个节点被以 和 两个计数器访问,那么这个节点就应该加入贡献。
然后这道题目就做完了,有什么疑问或写的不清晰的地方欢迎提出
最后放一份代码
#include <bits/stdc++.h> using namespace std; using uint = unsigned int; using ll = long long; using ull = unsigned long long; constexpr size_t N = 200005, M = 400005; int n, m; int head[N], nxt[M], to[M], cntg; int dfn[N], low[N], sta[N], belong[N], cntd, top, scc; bool vis[N][3];//vis[u][c]表示u是否被已c的计数器访问过 int res; void addEdge(int u, int v) { nxt[++cntg] = head[u]; to[cntg] = v; head[u] = cntg; } void tarjan(int u)//强连通分量 { dfn[u] = low[u] = ++cntd; sta[++top] = u; for (int e = head[u]; e > 0; e = nxt[e]) { int v = to[e]; if (dfn[v] == 0) { tarjan(v); low[u] = min(low[u], low[v]); } else if (belong[v] == 0) { low[u] = min(low[u], dfn[v]); } } if (dfn[u] == low[u]) { int v; scc++; do { v = sta[top--]; belong[v] = scc; } while (v != u); } } void dfs(int u, int c) { if (vis[u][c]) return; vis[u][c] = true; for (int e = head[u]; e > 0; e = nxt[e]) { int v = to[e]; if (belong[u] == belong[v])//保证在同一个强连通分量中 { dfs(v, (c == 2 ? 0 : c + 1)); } } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; int u, v; for (int i = 1; i <= m; i++) { cin >> u >> v; addEdge(u, v); } for (int i = 1; i <= n; i++) { if (dfn[i] == 0) { tarjan(i); } if (!vis[i][0] && !vis[i][1] && !vis[i][2])//这个节点的强连通分量没有被dfs过 { dfs(i, 0); } } for (int i = 1; i <= n; i++) { if ((vis[i][0] && vis[i][1]) || (vis[i][1] && vis[i][2]) || (vis[i][2] && vis[i][0])) { //这个节点被以两个相差1的计数器访问了,答案+1 res++; } } cout << res << '\n'; return 0; }
信息
- ID
- 2772
- 时间
- 2000ms
- 内存
- 128MiB
- 难度
- 6
- 标签
- (无)
- 递交数
- 41
- 已通过
- 8
- 上传者