• [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;
    }
     
    

      

  • 相关阅读:
    OA项目之分页
    OA项目之弹出层中再弹出层
    OA项目之导入
    OA项目之导出
    git使用6步走
    配置 Docker 镜像站
    Taro随笔
    byte(C# 参考)
    MySQL 笔记
    HTTP 错误代码
  • 原文地址:https://www.cnblogs.com/cutemush/p/14050436.html
Copyright © 2020-2023  润新知