C++ 洛谷 P2921 [USACO08DEC]在農場萬聖節Trick or Treat on the Farm 題解

mzyczly發表於2019-07-09

P2921 [USACO08DEC]在農場萬聖節Trick or Treat on the Farm

分析:

這棵樹上有且僅有一個環

兩種情況:

1.討論一個點在環上,如果在則答案與它指向點相同,

2.不在就等於它指向點答案+1,具體就直接大力dfs,

如何求環長度:

終點深度-起點深度=終點起點距離

#include<cstdio> 
#include<string>
#include<cstring>
using namespace std;
const int maxn=100005;
int n;
int cnt=1;
int a[maxn];
int h[maxn];
int ans[maxn];
int read() //快讀 
{
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
void dfs(int i,int deep)
{
    h[i]=deep;   //該點深度 
    if(ans[a[i]]) ans[i]=ans[a[i]]+1;   //若指向點有答案,而自己無答案,則自己不再環上。要+1 
    else if(h[a[i]])       //若形成環 
    {
        ans[i]=(h[i]-h[a[i]]+1);  //重新整理該點答案 
        int k=a[i];
        while(i!=k)   //重新整理環內所有答案 ,直到回到原點 
        {
            ans[k]=ans[i];  
            k=a[k];  
        }
    }
    else   
    {
        dfs(a[i],deep+1);
        if(!ans[i]) ans[i]=ans[a[i]]+1; //自身肯定不再環上,所以+1 
    }
}
void solve()
{
    for (int i=1;i<=n;i++)
    {
        if(!ans[i]) dfs(i,0);  //若此點未有涉及(無答案),就dfs 
    }
    for (int i=1;i<=n;i++)
    printf("%d\n",ans[i]);
}
void work()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
     a[i]=read();
    }
    solve();
}
int main()
{
    work();
    return 0;
}

相關文章