洛谷 P2661 信息传递 题解

这道题根据题意可以理解为在图中找一个最小环的问题

又因为题目中一条重要的性质:每个点出度都为1,所以我想到了一个删边的做法。

详细来讲就是递归删去除环以外的边(即原本或更新后入度为1的边),剩下一个个独立无交集的环,再遍历一遍就能找出答案。

注:每个点在删边和搜环时只会遍历一遍,所以程序并不会超时。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 200010
#define int long long
#define rep(i,s,e) for(register int i=s;i<=e;++i)
#define dwn(i,s,e) for(register int i=s;i>=e;--i)
using namespace std;
inline int read()
{
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}
    return f*x;
}
inline void write(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
int n,ans=99999999;
int a[maxn],r[maxn],book[maxn]; 
void remove(int x)
{
    --r[a[x]];
    book[x]=-1;
    if(r[a[x]]==0&&book[a[x]]==0) remove(a[x]);
}
void dfs(int x,int st,int step)
{
//    cout<<x<<" "<<st<<" "<<step<<endl;
//    getchar();
    if(x==st&&step!=0)
    {
        ans=min(ans,step);
        return;
    }
    book[x]=1;
    dfs(a[x],st,step+1);
}
signed main()
{
    n=read();
    rep(i,1,n) 
    {
        a[i]=read();
        ++r[a[i]];
    }
    rep(i,1,n)
    {
        if(r[i]==0&&book[i]!=-1) remove(i);
    } 
    rep(i,1,n)
    {
        if(book[i]==0) dfs(i,i,0);
    }
    cout<<ans;
    return 0;
}

 

posted @ 2020-09-04 21:17  handsome_zyc  阅读(219)  评论(0编辑  收藏  举报