传送门
可以用预处理后dfs搜索最小环来做,反正本蒟蒻用tarjan求最小强连通分量水过了,一开始感觉这样并不太严谨,因为最小的SCC不一定是最小环吧(最小环是最小的SCC的子集)。。。但是–几分钟后发现,对于所有点出度只有1的图来说,最小环好像一定是一个SCC,一定可以用tarjan搜出来!
不过,这个办法对于一般的有向图慎用!!!
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+2;
int n;
int head[MAXN],edge=0;
struct EDGE {
int v,nxt;
}e[MAXN];
int dfn[MAXN],low[MAXN],tim=0,snt=0,ans=0x3f3f3f3f;
bool ins[MAXN];
stack<int> S;
inline int read() {
int x=0;char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
inline void init() {
memset(dfn,0,sizeof(dfn)),
memset(head,-1,sizeof(head)),
memset(ins,false,sizeof(ins));
while (!S.empty()) S.pop();
}
inline void adde(int u,int v) {
e[edge].nxt=head[u],e[edge].v=v,head[u]=edge++;
}
void dfs(int p) {
dfn[p]=low[p]=++tim,
ins[p]=true,
S.push(p);
for (int i=head[p];~i;i=e[i].nxt) {
int v=e[i].v;
if (!dfn[v]) {
dfs(v);
low[p]=min(low[p],low[v]);
}
else if (ins[v]) low[p]=min(low[p],dfn[v]);
}
if (dfn[p]==low[p]) {
++snt;
int temp=0;
while (!S.empty()) {
int t=S.top();
S.pop();
ins[t]=false,
++temp;
if (t==p) break;
}
if (temp^1) ans=min(ans,temp);
}
}
int main() {
init();
n=read();
for (register int i=1;i<=n;++i) {
int v=read();
adde(i,v);
}
for (register int i=1;i<=n;++i)
if (!dfn[i]) dfs(i);
printf("%d\n",ans);
return 0;
}