https://www.luogu.org/problem/P2661
思路:其实就是求最小环。每个点的出度都是 1 1 1,因此构成的图要么是一条链+一个环,要么是几个环,通过拓扑可以消去链状的部分,对环的部分 d f s dfs dfs算最小环即可。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,tot=0,top=0,ans=INF;
int head[maxn],Stack[maxn],ind[maxn];
bool vis[maxn];
struct Edge
{
int to,nxt;
}edge[maxn<<1];
void addedge(int u,int v)
{
edge[++tot].to=v,edge[tot].nxt=head[u],head[u]=tot;
}
void topo()
{
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=edge[j].nxt)
ind[edge[j].to]++;
for(int i=1;i<=n;i++)
if(ind[i]==0)
Stack[++top]=i;
int tmp;
while(top)
{
tmp=Stack[top--];
vis[tmp]=1;
for(int i=head[tmp];i;i=edge[i].nxt)
if(--ind[edge[i].to]==0)
Stack[++top]=edge[i].to;
}
}
void dfs(int u,int len)
{
vis[u]=1;
int to;
for(int i=head[u];i;i=edge[i].nxt)
{
to=edge[i].to;
if(!vis[to])
dfs(to,++len);
else
{
ans=min(ans,len);
return ;
}
}
}
int main()
{
scanf("%d",&n);
int tmp;
for(int i=1;i<=n;i++)
{
scanf("%d",&tmp);
addedge(i,tmp);
}
topo();
for(int i=1;i<=n;i++)
if(!vis[i])
dfs(i,1);
printf("%d\n",ans);
}