题解:AcWing 517 信息传递

【题目来源】

AcWing:517. 信息传递 - AcWing题库

【题目描述】

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

【输入】

输入共\(2\)行。第\(1\)行包含\(1\)个正整数\(n\),表示\(n\) 个人。第\(2\)行包含\(1\sim n\),其中第\(i\)个整数\(T_i\)表示编号为\(i\)的同学的信息传递对象是编号为\(T_i\) 的同学,\(T_i\le n\)\(T_i\neq i\)。数据保证游戏一定会结束。

【输出】

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

【输入样例】

5
2 4 2 3 1

【输出样例】

3

【算法标签】

《AcWing 517 信息传递》 #并查集# #DFS# #找环#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

// 定义常量 N 和 INF,N 表示最大节点数,INF 表示无穷大
const int N = 200010, INF = 1e9;

// ind 数组记录每个节点的入度,h 数组记录每个节点指向的下一个节点
int ind[N], h[N];

// 队列 q 用于拓扑排序,st 数组记录节点是否被访问过
queue<int> q;
bool st[N];

// n 表示节点数
int n;

// 深度优先搜索函数,计算从节点 i 出发的最大深度
int dfs(int i, int dep) {
    st[i] = true; // 标记节点 i 已访问
    int res = dep; // 初始化结果为当前深度
    // 如果节点 h[i] 未被访问且入度大于 0,则继续搜索
    if (st[h[i]] == false && ind[h[i]] > 0)
        res = dfs(h[i], dep + 1);
    return res; // 返回最大深度
}

int main() {
    cin >> n; // 输入节点数
    // 读取每个节点指向的下一个节点,并更新入度数组
    for (int i = 1; i <= n; i++) {
        int j;
        cin >> j;
        h[i] = j;
        ind[j]++;
    }
    // 将所有入度为 0 的节点加入队列
    for (int i = 1; i <= n; i++) 
        if (ind[i] == 0) q.push(i);
    // 拓扑排序,减少每个节点指向的下一个节点的入度,如果入度变为 0,则加入队列
    while (!q.empty()) {
        int nd = q.front(); q.pop();
        ind[h[nd]]--;
        if (ind[h[nd]] == 0) q.push(h[nd]);
    }
    int ans = INF; // 初始化答案为无穷大
    // 对于每个入度大于 0 且未被访问的节点,计算其最大深度,并更新答案
    for (int i = 1; i <= n; i++) {
        if (ind[i] > 0 && st[i] == false) 
            ans = min(ans, dfs(i, 1));
    }
    cout << ans; // 输出结果
    return 0;
}

【运行结果】

5
2 4 2 3 1
3
posted @ 2026-02-19 15:28  团爸讲算法  阅读(10)  评论(0)    收藏  举报