P2661 信息传递 java代码题解

题目描述

有 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 nTin 且 T_i \neq iTii 。

输出格式:

输出共1行,包含1个整数,表示游戏一共可以进行多少轮。

解析:把每个同学看成一个点,信息的传递就是在他们之间连有向边,游戏轮数就是求最小环。

图论求最小环,我在里面看到了并查集。

假如说信息由A传递给B,那么就连一条由A指向B的边,同时更新A的父节点,A到它的父节点的路径长也就是B到它的父节点的路径长+1。这样我们就建立好了一个图,之后信息传递的所有环节都按照这些路径。游戏结束的轮数,也就是这个图里最小环的长度。

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


代码如下:

import java.util.Scanner;




public class huan {
//并查集的最小环
static int f[] = new int[200002];  //保存祖先节点
static int d[] = new int[200002];  //保存其祖先节点路径长
static int n,minn,last;


public static int  jion(int x) {
if(f[x]!=x) {   //查找是沿途更新祖先节点和路径长
last = f[x];  //记录父节点,会在递归中被更新
f[x] = jion(f[x]);//更新父节点
d[x]+=d[last];//更新路径长


}
return f[x];

}
public static void check(int a,int b) {

int x = jion(a),y = jion(b);   //查找祖先节点
if(x!=y) {
f[x]=y;   //若不相连,则连接两点,更新父节点和路径长
d[a]=d[b]+1;
}else {
minn = Math.min(minn, d[a]+d[b]+1);
}


}
public static void main(String[] args) {
Scanner input =  new Scanner(System.in);
int n =  input.nextInt();
for(int i=1;i<=n;i++) {
f[i] =i;
}

minn = Integer.MAX_VALUE;
  for(int i =1;i<=n;i++) {
  int t = input.nextInt();
  check(i,t);
  }
  System.out.println(minn);
}




}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值