去题面的传送门
QAQ这题有两种做法
Solution 1: 暴力找环
很明显题目是让找最小环,那我们就顺着找呗。一开始尝试用递归做,弄了半天也不行,不太好记录已经跑过了几个点。
其实每一个点的出度都是1,所以不用存图,直接一个数组记录每一个点连接的下一个节点是哪一个就行了。
记得还要for一遍,确定每一个点都跑过。
但是一开始这样交超时了。
后来发现,其实每次从一个点开始找环的时候,如果直接找到的下一个点是之前访问过的,直接return就好了
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200000+10;
int n,ans,tot;
int nxt[maxn],pre[maxn],cnt[maxn];
void done(int x)
{
int now=x,num=0;
while(true)
{
num++;
if(pre[now])
{
if(pre[now]==x) ans=min(ans,num-cnt[now]);
break;
}
cnt[now]=num;
if(!pre[now]) tot++;
pre[now]=x;
now=nxt[now];
}
}
int main()
{
scanf("%d",&n);
ans=2147483647;
for(int i=1;i<=n;++i) scanf("%d",&nxt[i]);
for(int i=1;i<=n;++i)
{
if(tot==n) break;
if(!pre[i]) done(i);
}
printf("%d",ans);
return 0;
}
Solution 2:tarjan找环
很简单,打了一遍没调就过了
直接上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
const int maxn=200000+10;
int n,scc_cnt,Index,ans;
int nxt[maxn],scc[maxn],dfn[maxn],low[maxn];
vector<int>incom[maxn];
stack<int>s;
void tarjan(int i)
{
dfn[i]=low[i]=++Index;
s.push(i);
if(!dfn[nxt[i]])
{
tarjan(nxt[i]);
low[i]=min(low[i],low[nxt[i]]);
}
else if(!scc[nxt[i]]) low[i]=min(dfn[nxt[i]],low[i]);
if(low[i]==dfn[i])
{
scc_cnt++;
int j;
do
{
j=s.top();
s.pop();
incom[scc_cnt].push_back(j);
scc[j]=scc_cnt;
}
while(i!=j);
}
}
int main()
{
scanf("%d",&n);
ans=2147483647;
for(int i=1;i<=n;++i) scanf("%d",&nxt[i]);
for(int i=1;i<=n;++i)
if(!scc[i]) tarjan(i);
for(int i=1;i<=scc_cnt;++i)
{
int x=incom[i].size();
if(x>1)
ans=min(ans,x);
}
printf("%d",ans);
return 0;
}