• P2661 信息传递


    题意:

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

    输入输出样例

    输入样例
    5
    2 4 2 3 1
    输出样例
    3

    说明

    样例1解释

    游戏的流程如图所示。当进行完第3 轮游戏后, 4号玩家会听到 2 号玩家告诉他自己的生日,所以答案为 3。当然,第 3 轮游戏后,2号玩家、 3 号玩家都能从自己的消息来源得知自己的生日,同样符合游戏结束的条件。

    对于 30%的数据, n ≤ 200

    对于 60%的数据, n ≤ 2500

    对于100%的数据, n ≤ 200000

    并查集判最小环

    假设信息由A传递给B,那么就连一条由A指向B的边,同时更新A的父节点,A到它的父节点的路径长也就是B到它的父节点的路径长+1。

    这样我们就建立好了一个图,之后信息传递的所有环节都按照这些路径。游戏结束的轮数,也就是这个图里最小环的长度。

    如果有两个点祖先节点相同,那么就可以构成一个环,长度为两个点到根节点长度之和+1。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    #define olinr return
    #define _ 0
    #define love_nmr 0
    #define DB double
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
            if(ch=='-')
                f=-f;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    inline void put(int x)
    {
        if(x<0)
        {
            x=-x;
            putchar('-');
        }
        if(x>9)
            put(x/10);
        putchar(x%10+'0');
    }
    int f[205050];
    int dis[205050];
    int ans=0x7fffffff;
    int n;
    inline int findset(int x)
    {
        if(x!=f[x])
        {
            int fa=f[x];
            f[x]=findset(f[x]);   //路径压缩 
            dis[x]+=dis[fa];    //记录到根的路径长
        }
        return f[x];
    }
    inline void doit(int x,int y)
    {
        int xx=findset(x);   //找到根
        int yy=findset(y);
        if(xx!=yy)   //不在一个集合(不会得到自己生日的信息)
        {
            f[xx]=yy;
            dis[x]=dis[y]+1;
        }
        else
            ans=min(ans,dis[x]+dis[y]+1);  //求最小环长度
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
            f[i]=i;
        for(int i=1;i<=n;i++)
            doit(i,read());
        put(ans);
        olinr ~~(0^_^0)+love_nmr;
    }
  • 相关阅读:
    mkdir命令
    pwd命令
    chmod命令
    chown命令
    chgrp命令
    687. Longest Univalue Path
    HYSBZ 1036 树的统计Count (水题树链剖分)
    POJ 3709 K-Anonymous Sequence (斜率优化DP)
    LightOJ 1065 Island of Survival (概率DP?)
    LightOJ 1248 Dice (III) (水题,期望DP)
  • 原文地址:https://www.cnblogs.com/olinr/p/9560686.html
Copyright © 2020-2023  润新知