题解:可以看出这个题是一个求图的最小环的板题
一:先找出入度为0的点,把这些点以及这些出边删去,最后剩余的跑出最小环
附上代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+50;
int in[maxn],book[maxn],mapp[maxn],ans,temp;
void dfs(int beginn)
{
book[beginn]=1;
in[mapp[beginn]]--;
if(in[mapp[beginn]]==0){
dfs(mapp[beginn]);
}
}
void dfs1(int anc,int beginn)
{
book[beginn]=1;
temp++;
if(mapp[beginn]==anc){
return ;
}else{
dfs1(anc,mapp[beginn]);
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&mapp[i]);
in[mapp[i]]++;
}
for(int i=1;i<=n;i++){
if(in[i]==0&&!book[i]){
dfs(i);
}
}
ans=0x3f3f3f3f;
for(int i=1;i<=n;i++){
if(in[i]&&!book[i]){
temp=0;
dfs1(i,i);
ans=min(ans,temp);
}
}
printf("%d\n",ans);
return 0;
}
二:使用tarjan直接更新出最小环(最小环至少长度为2)即可
附上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=2e5+50;
struct edge{
int v,next;
};
edge edges[maxn];
int head[maxn],cnt;
int dfn[maxn],low[maxn],stack[maxn],visit[maxn],tot,iindex;
int ans=0x3f3f3f3f,temp;
int n,v;
void add(int x,int y)
{
edges[cnt].v=y;
edges[cnt].next=head[x];
head[x]=cnt++;
}
void tarjan(int x)
{
dfn[x]=low[x]=++tot;
stack[++iindex]=x;
visit[x]=1;
for(int i=head[x];~i;i=edges[i].next){
if(!dfn[edges[i].v]){
tarjan(edges[i].v);
low[x]=min(low[x],low[edges[i].v]);
}else if(visit[edges[i].v]){
low[x]=min(low[x],dfn[edges[i].v]);
}
}
temp=0;
if(low[x]==dfn[x]){
do{
temp++;
visit[stack[iindex]]=0;
iindex--;
}while(x!=stack[iindex+1]);
if(temp>1){
ans=min(ans,temp);
}
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&v);
add(i,v);
}
tot=0,iindex=0;
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i);
}
}
printf("%d\n",ans);
return 0;
}