【内向基环树】codeforces 2044 G1. Medium Demon Problem (easy version)
前言
基环树,又名环套树,是具有 \(n\) 个节点和 \(n\) 条边的图,比树多出现一个环。基环树也根据边的有向和无向分为了有向基环树和无向基环树。有向基环树又可以分为内向基环树和外向基环树。对于有向基环树,若基环树的每个节点的出度均为 \(1\),则称为内向基环树;若基环树的每个节点的入度均为 \(1\),则称为外向基环树;由多棵内向基环树组成的森林,则称为内向基环树森林;由多棵外向基环树组成的森林,称为外向基环树森林。求环可以用拓扑排序或者 DFS。

题目
https://codeforces.com/contest/2044/problem/G1
题解
分析题意,易知该题符合内向基环树森林的特征。
由于每个蜘蛛手上至多只会保留一个毛绒玩具,因此对于任意一颗内向基环树的简单环而言,都是永远相等的。因此,我们只需要关注内向基环树的外链最长长度即可。对于内向基环树的外链长度,可以使用拓扑排序的思路进行解决,由于环上节点入度必不为 \(0\),因此环上节点不会被计算在内,故而使用拓扑排序是可以求解出内向基环树森林中最长的外链长度的。
因为题目要求要 \(2\) 轮相同才视为状态稳定,所以最后答案就是最长外链长度 + \(2\)。
参考代码
#include<bits/stdc++.h>
using namespace std;
constexpr int N = 2e5 + 7;
int T, n;
int a[N];
int in[N];
void solve() {
cin >> n;
memset(in + 1, 0, sizeof(int) * n);
for (int i = 1; i <= n; ++ i) {
cin >> a[i];
in[a[i]] ++;
}
vector<int> v;
for (int i = 1; i <= n; ++ i) if (!in[i]) v.emplace_back(i);
int ans = 2, front = 0, rear = v.size();
while (front < rear) {
++ ans;
while (front < rear) {
if (-- in[a[v[front]]] == 0) v.emplace_back(a[v[front]]);
++ front;
}
rear = v.size();
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> T;
while (T --) {
solve();
}
return 0;
}
浙公网安备 33010602011771号