思路是
先用并查集把有关联的点都连接起来,再每个点进行遍历,对于每个连通块的祖先节点进行标记,发现遍历了两次的点后从发现环的点开始跑,记录经过的边数,直到再次遇到该点。
每个连通块应该只会被访问一次,全图遍历复杂度为 O(2n) 吧。为什么会T呢?
代码在这里了
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
ll num = 0;
ll x = 1;
char ch = getchar();
while( !isdigit(ch) ){
if( ch == '-' )
x = -1;
ch = getchar();
}
while( isdigit(ch) ){
num = num * 10 + ch - '0';
ch = getchar();
}
return num * x;
}
bool vis[200005];
int nxt[200005];
int fa[200005];
int ff( int x ){
return x == fa[x] ? x : fa[x] = ff(fa[x]);
}
void mg( int x, int y ){
fa[ff(x)] = ff(y);
}
int t;
int main(){
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
freopen( )
int n;
n = read();
for( int i = 1; i <= n; i++ )
fa[i] = i;
for( int i = 1; i <= n; i++ ){
cin >> nxt[i];
mg( i,nxt[i] );
}
int ans = 1e9;
for( int i = 1; i <= n; i++ ){
if( !vis[fa[i]] ){
int p = 0;
vis[fa[i]] = 1;
int j = nxt[fa[i]];
for( ; ; j = nxt[j] ){
if( vis[j] ){
p = j;
break;
}
vis[j] = 1;
}
int cnt = 0;
j = p;
do{
cnt++;
j = nxt[j];
}
while( j!=p );
ans = min( ans,cnt );
}
else
continue;
}
cout << ans;
return 0;
}