题目:https://www.luogu.org/problem/P2661
分析:求最小环。
解法一:深搜或广搜,利用时间戳求出各个环的长度。
解法二:用tarjan求CSS。
AC代码一(解法一):
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,m,x,y;
struct Edge{
int from,to,next;
};
Edge edge[200005];
int num=0,head[200005];
int a[200005],minn=200005;
int vis[200005],cns,que[200005];
void join(int from,int to){
edge[++num].next=head[from];
edge[num].from=from;
edge[num].to=to;
head[from]=num;
}
void bfs(int x){
vis[x]=++cns;
a[x]=1;
int hd=0,tl=1;
que[1]=x;
while(hd<tl){
hd++;
int now=que[hd];
for(int i=head[now]; i!=-1; i=edge[i].next){
int to = edge[i].to;
if( a[to]==0 ) {
que[++tl]=to;
a[to]=a[now]+1;
vis[to]=cns;
}
else if(vis[now]==vis[to] && minn>a[now]-a[to]+1)
minn=a[now]-a[to]+1;
}
}
}
int main(){
memset(head,-1,sizeof(head));
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
join(i,x);
}
for(int i=1;i<=n;i++)
if(a[i]==0)
bfs(i);
cout<<minn<<endl;
return 0;
}
AC代码二(解法二):
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MaxN=2e5+5;
int n,x,ans=1e9;
inline int get(){//读入优化
char c=getchar();
int x=0;
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9'){
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
return x;
}
int tot,nex[MaxN],from[MaxN],to[MaxN],head[MaxN];
void join(int x,int y){
nex[++tot]=head[x];
from[tot]=x;
to[tot]=y;
head[x]=tot;
}
int num,dfn[MaxN],low[MaxN],st[MaxN],top,col,co[MaxN],si[MaxN];
void Tarjan(int u){//求SCC
dfn[u]=low[u]=++num;
st[++top]=u;
for(int i=head[u];i;i=nex[i]){
int v=to[i];
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!co[v])low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){//不在上面的for里面!!
int cns=0;
co[u]=++col;
cns++;//统计最小环
++si[col];
while(st[top]!=u){
co[st[top]]=col;
cns++;
++si[col];
--top;
}
--top;
if(ans>cns && cns>1)ans=cns;
}
}
int main(){
n=get();
for(int i=1;i<=n;i++){
x=get();
join(i,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i])Tarjan(i);
cout<<ans;
return 0;
}