首页 > 其他 > 详细

[洛谷] P2661 信息传递

时间:2019-07-26 23:01:53      阅读:83      评论:0      收藏:0      [点我收藏+]

题目描述

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

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

输入格式

2行。

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

2行包含 nn 个用空格隔开的正整数 T_1,T_2,\cdots\cdots,T_nT1?,T2?,??,Tn? ,其中第 ii 个整数 T_iTi? 表示编号为 ii 的同学的信息传递对象是编号为 T_iTi? 的同学, T_i \leq nTi?n 且 T_i \neq iTi?i 。

 

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

输入:

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

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

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

学业繁忙,告辞

[洛谷] P2661 信息传递

原文:https://www.cnblogs.com/JNzH/p/11253053.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!