补题计划开始。
求一个有向图的最小环。该图所有点的出度均为 \(1\)。
数据范围:\(1\le n\le 2 \times 10^5\) 。
被样例误导,以为该图一定是连通的,于是认为整个图只有一个环,然后利用该性质进行解题。
错误代码很简单,就是找到唯一的环然后计算长度,容易误以为是正解实际只有 \(40 \text{pts}\) 。
碰到这种错误就 remake 吧。
一个做法是 dfs 染色,这种做法很契合题目的出题意图,我特别想写这种做法但是写挂了。
考虑并查集求最小环。每一次都要判断两点间是否有边。无边则连上,有边则更新最小环大小。
如果有两个点祖先节点相同,那么就可以构成一个环,长度为两个点到祖先节点长度之和加 \(1\)。
要直接在并查集上面改哦。具体的看代码。
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int maxn = 200005; const int inf = 0x7fffffff; int n, a[maxn]; int f[maxn], d[maxn]; // f 保存祖先节点,d 保存到其祖先节点的路径长 int minn = inf; int find(int x) { if (f[x] != x) { int last = f[x]; f[x] = find(f[x]); d[x] += d[last]; } return f[x]; } void check(int a,int b) { int x = find(a), y = find(b); if (x != y) { f[x] = y; d[a] = d[b] + 1; } else minn = min(minn, d[a] + d[b] + 1); return; } int main() { cin >> n; for(int i = 1; i <= n; i ++) f[i] = i; for(int i = 1; i <= n; i ++) { int t; cin >> t; check(i, t); } cout << minn << endl; }