• [洛谷] P2661 信息传递 (简单图论)


    题目描述

    有 nn 个同学(编号为 11 到 nn )正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为 ii 的同学的信息传递对象是编号为 T_iTi 的同学。

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

    输入格式

    2行。

    1行包含1个正整数 nn ,表示 nn 个人。

    2行包含 nn 个用空格隔开的正整数 T_1,T_2,cdotscdots,T_nT1,T2,,Tn ,其中第 ii 个整数 T_iTi 表示编号为 ii 的同学的信息传递对象是编号为 T_iTi 的同学, T_i leq nTin 且 T_i eq iTii 。

    题意:求一个有向图的最小环

    输入:

    5
    2 4 2 3 1

    输出:

    3

    思路:由于每一个人只有一个操作对象,那么这个有向图每一个连通分支必定有一个环

    那么我的做法就是对于在所有标记为0的点开始DFS,对其中经过的点打上某一次DFS的标记,

    在对某些遍历过的连通分支的标记为0的点进行操作时,直接跳出。

    每次找到环之后计算出所用的轮数,直到所有的点的标记都不为0。预计时间复杂度为 O(n)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int MAXN=2e5+10;
    int vis[MAXN];
    int nx[MAXN],lp;
    int cur[MAXN];
    int ans=0x3f3f3f3f;
    
    void dfs(int st)
    {
        lp++;
        int cnt=0,t=st;
        while(vis[t]==0)
        {
            cur[t]=cnt;
            cnt++;
            vis[t]=lp;                            //做上趟数标记
            t=nx[t];
            if(vis[t]!=lp&&vis[t]!=0)      //发现是之前操作过的连通分支,则跳出      
                return ;
        }
        ans=min(ans,cnt-cur[t]);
    }
    
    int main()
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;++i)
            scanf("%d",&nx[i]);
        for(int i=1;i<=n;++i)
        {
            if(!vis[i])    dfs(i);
        }
        cout<<ans;
        return 0;
    }                

    判断是否属于同一连通分支也可以用并查集,但是这里地方太小,我写不下(滑稽)

    等改天有时间了(?),就来写一下并查集的做法。(也许不咕)

    学业繁忙,告辞

    
    
  • 相关阅读:
    JS 面向对象
    inline-block元素间隙处理
    MUI
    MUI
    chrome://inspect调试html页面空白,DOM无法加载的解决方案
    MUI
    MUI
    MUI
    MUI
    MUI
  • 原文地址:https://www.cnblogs.com/JNzH/p/11253053.html
Copyright © 2020-2023  润新知