版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/guapi2333/article/details/83315265
一道不错的记搜题。
由于每一个人点的出度只能是1,所以我们不难发现:每一条在环上的边只能属于一条环。换句话说:任何一条边顶多属于一个环。这样我们就可以用简单的记搜来实现。
设为从点开始最多能到达的点的总个数,那么显然,当在某个环中,=其他环上的点的f的值;当不在环中时,=从出发最先能到达的环中的点与的距离+。
具体的实现细节见代码。
Code:
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=100020;
int n,nxt[MAXN],fst,dfn[MAXN],huan[MAXN],f[MAXN];
inline int read()
{
int x=0;
char ch=getchar();
while(ch<'0'||'9'<ch) ch=getchar();
while('0'<=ch&&ch<='9')
{
x=(x <<3)+(x <<1)+(ch-'0');
ch=getchar();
}
return x;
}
void dfs(int x,int tim)
{
if(nxt[x]==x) { f[x]=1; return; }//一定记得判断自环的情况
if(f[nxt[x]]>0) { f[x]=f[nxt[x]]+1; return; }
dfn[x]=tim;
if(dfn[nxt[x]]>0)
{
huan[x]=1; fst=nxt[x];//huan变量帮助判断当前点是否在环上
f[x]=dfn[x]-dfn[nxt[x]]+1;
//记录dfs序:当某个点通往一个已被搜到的点nxt[x],说明从nxt[x]到x的路径+单向边w(x,nxt[x])已经构成了一个环。
//显然这个环的长度=dfn[x]-dfn[nxt[x]]+1;
return;
}
dfs(nxt[x],tim+1);
if(huan[nxt[x]]==1)
{
huan[x]=1; f[x]=f[nxt[x]];
if(x==fst) huan[x]=0;
return;
}
f[x]=f[nxt[x]]+1;
return;
}
int main()
{
n=read();
for(int i=1;i<=n;i++) nxt[i]=read();
for(int i=1;i<=n;i++)
{
fst=0;
if(!dfn[i]) dfs(i,1);
}
for(int i=1;i<=n;i++) cout<<f[i]<<'\n';
return 0;
}