这道题根据题意可以理解为在图中找一个最小环的问题
又因为题目中一条重要的性质:每个点出度都为1,所以我想到了一个删边的做法。
详细来讲就是递归删去除环以外的边(即原本或更新后入度为1的边),剩下一个个独立无交集的环,再遍历一遍就能找出答案。
注:每个点在删边和搜环时只会遍历一遍,所以程序并不会超时。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 200010 #define int long long #define rep(i,s,e) for(register int i=s;i<=e;++i) #define dwn(i,s,e) for(register int i=s;i>=e;--i) using namespace std; inline int read() { int x=0,f=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();} return f*x; } inline void write(int x) { if(x<0){putchar('-');x=-x;} if(x>9)write(x/10); putchar(x%10+'0'); } int n,ans=99999999; int a[maxn],r[maxn],book[maxn]; void remove(int x) { --r[a[x]]; book[x]=-1; if(r[a[x]]==0&&book[a[x]]==0) remove(a[x]); } void dfs(int x,int st,int step) { // cout<<x<<" "<<st<<" "<<step<<endl; // getchar(); if(x==st&&step!=0) { ans=min(ans,step); return; } book[x]=1; dfs(a[x],st,step+1); } signed main() { n=read(); rep(i,1,n) { a[i]=read(); ++r[a[i]]; } rep(i,1,n) { if(r[i]==0&&book[i]!=-1) remove(i); } rep(i,1,n) { if(book[i]==0) dfs(i,i,0); } cout<<ans; return 0; }