top1编程
← 返回题目
题解

【基础】信息传递

1 条题解

  • 0
    @ 2026-7-29 0:18:59
    #include <bits/stdc++.h>
    
    using namespace std;
    
    /**
    思路:其实就是求最小环。每个点的出度都是1,因此构成的图要么是一条链+一个环,要么是几个环,
    通过拓扑可以消去链状的部分,对环的部分dfs算最小环即可。
    */
    const int N = 2e5 + 10;
    
    int n;                  //n个同学
    int ans = 0x3f3f3f3f;   //答案,初始值为极大值
    vector<int> edge[N];    //邻接表
    int ind[N];             //入度数组
    queue<int> q;           //拓扑排序用的队列
    bool st[N];             //是不是已经被排除掉
    
    //拓扑排序[这是一个拓扑排序的模板,但里面扩充了本题的st[i]数组标识 ]
    void topsort() {
        //入度为0的结点入队列
        for (int i = 1; i <= n; i++) if (!ind[i]) q.push(i);
        //图的广度优先遍历
        while (!q.empty()) {
            int x = q.front();
            q.pop();
            //标识非环中结点
            st[x] = true;
            //遍历每条出边
            for (int i = 0; i < edge[x].size(); i++) {
                int y = edge[x][i];
                ind[y]--;
                if (!ind[y]) q.push(y);//在删除掉当前结点带来的入度后,是不是入度为0了,如果是将点y入队列
            }
        }
    }
    
    /**
     功能:求图中包含点u的环的长度
     参数: u   结点
           len 长度
     */
    void dfs(int u, int len) {
        //标识探测过了
        st[u] = true;
        //遍历所有u开头的边
        for (int y:edge[u]) {
            //如果这个点还没有被探测过,那么继续探索
            if (!st[y]) dfs(y, ++len);
            else { //到这里是发现了环!因为现在在邻接表中只剩下了环,其它的链路都被拓扑排序干掉了,
                // 结果还是出现访问过的结点,就肯定是发现环了
                ans = min(ans, len); //这是递归的出口.此处和其它的递归不一样啊,递归出口居然在代码区,
                // 而不是在一进递归的位置~
                return;
            }
        }
    }
    
    int main() {
        //创建有向图
        cin >> n;
        for (int i = 1; i <= n; i++) {
            int u;
            cin >> u;
            //邻接表方式
            edge[i].push_back(u);
            //入度++
            ind[u]++;
        }
        //拓扑排序
        topsort();
    
        //到这里,st[i]=false的就应该是环中结点,对环的部分dfs算最小环即可
        for (int i = 1; i <= n; i++) if (!st[i]) dfs(i, 1);
        cout << ans << endl;
    }
    
    • 1