目录
显示
题目链接
https://www.luogu.org/problem/P2661
题解
本题的任务是让我们在有向图中找一个最小环。
我们每次选一个还没有遍历的节点开始遍历。如果我们遍历到一个没有遍历过的点,记录这个点的遍历顺序,然后继续向下遍历。
如果这个节点已经被遍历,那么又分为两种情况:第一种是在这一次遍历中之前遍历的节点,在这种情况下,我们找到了一个环,这时我们可以直接与目前的最小环作比较,更新答案。
如果这个节点在以前的遍历中已经遍历过,我们就可以停止这一轮的遍历了。原因在于:无论我们遍历到的这个点是不是环上的点,都不会使答案更优。
当所有的点都被遍历时,就可以输出答案了。
显然,该算法的复杂度是 \(O(n)\) 的。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int t[200005],vis[200005],cyc[200005];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&t[i]);
int ans=200005;
for(int i=1;i<=n;i++)
{
if(vis[i]==-1)continue;
cyc[1]=i;
vis[i]=1;
int cnt=1,cur=i;
while(1)
{
cur=t[cur];
cyc[++cnt]=cur;
if(vis[cur]==-1)
{
for(int i=1;i<=cnt;i++)
vis[cyc[i]]=-1;
break;
}
if(vis[cur]>0)
{
ans=min(ans,cnt-vis[cur]);
for(int i=1;i<=cnt;i++)
vis[cyc[i]]=-1;
break;
}
vis[cur]=cnt;
}
}
printf("%d\n",ans);
return 0;
}