[Noip2015] 信息传递

有n个同学(编号为1到n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号
为i的同学的信息传递对象是编号为Ti同学。游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同
时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息,但是每人只
会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一
共可以进行几轮? 简单的说就是给你一个有向图,让你找出一个最小的环来。

输入

输入共2行。 
第1行包含1个正整数n表示n个人。 n ≤ 200000 
第2行包含n个用空格隔开的正整数T1,T2,……,Tn
其中第i个整数Ti示编号为i的同学的信息传递对象是编号为Ti的同学,Ti≤n且Ti≠i 
数据保证游戏一定会结束。 

输出

输出共 1 行,包含 1 个整数,表示游戏一共可以进行多少轮。

样例

输入

复制
5 
2 4 2 3 1 

输出

复制
3 
Sol1:topsort
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=200000+10;
int to[maxn],into[maxn],n,q[maxn],ans=1e7;
bool vis[maxn];
void bfs()
{
int head=0,tail=0;
for(int i=1; i<=n; i++)
if(!into[i]) //将入度为0的点进队列
{
vis[i]=1;
tail++;
q[tail]=i;
}
head=1;
while(head<=tail)
{
into[to[q[head]]]--;
if(!into[to[q[head]]])
{
tail++;
q[tail]=to[q[head]];
vis[q[tail]]=1;
}
head++;
}
}
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
     scanf("%d",&to[i]);
     into[to[i]]++;
}
bfs();
for(int i=1; i<=n; i++)
{
int cnt=0;
if(!vis[i])
{
    int k=i;
    while(!vis[k])
    {
       vis[k]=1;
       k=to[k];
       cnt++;
    }
    ans=min(cnt,ans);
}
}
cout<<ans;
return 0;
}

  并查集

#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
 
const int inf=1e9;
const int N=200020;
int n,m,step,ans;
int d[N],num[2010],e[N],ne[N],idx,w[N],st[2010],h[N],f[N];
int a[N],vis[N],cnt[N];
typedef pair<int ,int > PII;
 
 
 
 
 
/*并查集做法*/
int find(int x)
{
    if(x!=f[x])
    {
        int z=f[x];
        f[x]=find(f[x]);
        d[x]=d[x]+d[z];
    }
    return f[x];
}
 
void Union(int x,int y)
{
    int fa=find(x);
    int fy=find(y);
    if(fa==fy)
        ans=min(ans,d[x]+d[y]+1);
		//有相同父节点说明本来就在同一条链上,
		//再加上他们之间的边所以形成环,更新最小环
    else
    {
        f[fa]=fy;
        d[x]=d[y]+1;
    }
}
int main()
{
    cin>>n;
    ans=inf;
    for(int i=1;i<=n;i++)
        f[i]=i;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        Union(i,a[i]);
    }
    cout<<ans<<endl;
    return 0;
}
 

  

posted @ 2020-11-27 21:29  我微笑不代表我快乐  阅读(146)  评论(0编辑  收藏  举报