题目链接:https://www.luogu.org/problemnew/show/P2661
题目描述:
有n个同学(编号为1到n )正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,
其中,编号为i的同学的信息传递对象是编号为Ti的同学。
游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息, 但是每人只会把信息告诉一个人,即自己的信息传递对象)。
当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?
思路:可以用并查集求最小回路。可以比作有向图,每个点出度都为1,即每个点只有一条边可以到其他点。
如果有一个传递关系:A -> B, B->C, C->A,说明要传递3次才能有人会被告知自己的生日,那么在并查集可以fa[C] = B ,f[B] = A, f[A] = A,
模拟了信息完全的的传递,而且“
当有人从别人口中得知自己的生日时,游戏结束”,那么我们要维护一个最小值,即最少传递回合,满足题意。
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <cstdio> 5 #include <vector> 6 #include <string> 7 using namespace std; 8 9 typedef long long LL; 10 #define inf (1LL << 30) - 1 11 #define rep(i,j,k) for(int i = (j); i <= (k); i++) 12 #define rep__(i,j,k) for(int i = (j); i < (k); i++) 13 #define per(i,j,k) for(int i = (j); i >= (k); i--) 14 #define per__(i,j,k) for(int i = (j); i > (k); i--) 15 16 const int N = (int)2e5 + 10; 17 int fa[N]; 18 int G[N]; 19 int n,v; 20 int ans = inf; 21 22 void init(){ 23 rep(i,1,n) fa[i] = i; 24 } 25 26 int search(int x, int& cnt){ 27 28 ++cnt; //回路的深度 29 if(fa[x] == x) return x; 30 else return search(fa[x], cnt); 31 } 32 33 int main(){ 34 35 ios::sync_with_stdio(false); 36 cin.tie(0); 37 38 cin >> n; 39 init(); 40 41 rep(i,1,n){ 42 43 int cnt = 0; 44 45 cin >> v; 46 if(search(v,cnt) == i){ 47 ans = min(ans,cnt); //找到了回路,并维护最小回路 48 } 49 else { 50 fa[i] = v;// i -> v 51 } 52 } 53 cout << ans << endl; 54 getchar();getchar(); 55 return 0; 56 }