洛谷 信息传递之图中寻找最小环(图论)

时间:2022-06-01 17:56:28

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

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

#include<bits/stdc++.h>

using namespace std;
const int MAXN = 200005;
int n,num[MAXN],ans = MAXN;
int used[MAXN],times[MAXN];
void dms(int x){//寻找最小环
    int clocks = 0,p = x;//p表示哪一个同学,clock是当前步数;
    while(true){//先执行,后作判断
        used[p] = x,times[p] = clocks ++,p = num[p];
        if(used[p]){if(used[p] == x) ans = min(ans,clocks - times[p]); break; }
    }

}

//此处以
5
2 4 2 3 1 数据为例
第一步:
used[1]=1;times[1]=0;clock=1;p=num[1]=2;p指向与1相连的2;
第二步:
used[2]=1;times[2]=1;clock=2;p=num[2]=4;p指向与2相连的4;
第三步:
used[4]=1;times[4]=2;clock=3;p=num[p]=3;p指向与4相连的3;
第四步:
used[3]=1;times[3]=3;clock=4;p=num[p]=2;p指向与3相连的2;
此后  used[2],used[2]=1;ans=4-1=3;
这时与1相连的成员全部遍历完全,后续只用遍历未与1相连的成员即可,ans不断更新最小值

int main()
{
    memset(times,0,sizeof(times));
    memset(used,0,sizeof(used));
    scanf("%d",&n);
    for(int i = 1; i <= n; i ++) scanf("%d",&num[i]);
    for(int i = 1; i <= n; i ++) if(!used[i]) dms(i);
    printf("%d\n",ans);
    return 0;
}