• acwing算法提高之图论--拓扑排序


    1 介绍

    本专题用来记录拓扑排序相关的题目。

    求拓扑序列算法的关键步骤

    1. 把入度为0的结点插入队列q。
    2. 弹出队头t(将t记录下来),遍历队头t的下一个结点,将其入度减1。操作之后,如果其值为0,则插入队列q。
    3. 重复进行步骤2,直至队列q为空。
    4. 弹出的元素组成的序列就是一个拓扑序列。

    有向无环图等价于图中存在拓扑序列

    2 训练

    题目11191家谱树

    C++代码如下,

    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 110;
    int n;
    int din[N];
    vector<vector<int>> g(N);
    
    int main() {
        cin >> n;
        for (int i = 1; i <= n; ++i) {
            int t;
            while (cin >> t, t) {
                g[i].emplace_back(t);
                din[t]++;
            }
        }
        
        queue<int> q;
        for (int i = 1; i <= n; ++i) {
            if (din[i] == 0) {
                q.push(i);
            }
        }
        
        vector<int> res;
        while (!q.empty()) { //队列中存储的是,目前所有入度为0的结点
            int a = q.front();
            q.pop();
            res.emplace_back(a);
            
            for (auto b : g[a]) {
                din[b]--;
                if (din[b] == 0) {
                    q.push(b);
                }
            }
        }
        
        for (auto x : res) cout << x << " ";
        cout << endl;
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    题目21192奖金

    C++代码如下,

    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 10010;
    int n, m;
    vector<vector<int>> g(N);
    int dist[N];
    int din[N];
    
    int main() {
        cin >> n >> m;
        for (int i = 0; i < m; ++i) {
            int a, b;
            cin >> a >> b;
            g[b].emplace_back(a);
            din[a]++;
        }
        
        memset(dist, 0x3f, sizeof dist);
        
        queue<int> q;
        for (int i = 1; i <= n; ++i) {
            if (din[i] == 0) {
                q.push(i);
                dist[i] = 100;
            }
        }
        
        int cnt = 0;//入度为0的结点总数
        while (!q.empty()) {
            int a = q.front();
            q.pop();
            cnt++;
            
            for (int b : g[a]) {
                din[b]--;
                if (din[b] == 0) {
                    q.push(b);
                    dist[b] = dist[a] + 1;
                }
            }
        }
        
        if (cnt != n) puts("Poor Xed");
        else {
            int sum = 0;
            for (int i = 1; i <= n; ++i) sum += dist[i];
            cout << sum << endl;
        }
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    题目3164可达性统计

    C++代码如下,

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 30010;
    int n, m;
    int din[N];
    bitset<N> f[N]; //f[i]表示结点i能走到的结点
    vector<vector<int>> g(N);
    vector<int> res;
    
    void toposort() {
        queue<int> q;
        for (int i = 1; i <= n; ++i) {
            if (din[i] == 0) {
                q.push(i);
            }
        }
        
        while (!q.empty()) {
            int a = q.front();
            q.pop();
            res.emplace_back(a);
            
            for (auto b : g[a]) {
                din[b]--;
                if (din[b] == 0) {
                    q.push(b);
                }
            }
        }
        
        return;
    }
    
    int main() {
        cin >> n >> m;
        for (int i = 0; i < m; ++i) {
            int a, b;
            cin >> a >> b;
            din[b]++;
            g[a].emplace_back(b);
        }
        
        toposort();
        
        for (int i = res.size() - 1; i >= 0; --i) {
            int a = res[i];
            f[a][a] = 1;
            for (auto b : g[a]) {
                f[a] |= f[b];
            }
        }
        
        for (int i = 1; i <= n; ++i) {
            cout << f[i].count() << endl;
        }
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    题目4456车站分级

    C++代码如下,

    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 2010, M = 1000010;
    
    int n, m;
    int h[N], e[M], ne[M], w[M], idx;
    int q[N], d[N];
    int dist[N];
    bool st[N];
    
    void add(int a, int b, int c) {
        e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
        d[b]++;
    }
    
    void topsort() {
        int hh = 0, tt = -1;
        for (int i = 1; i <= n + m; ++i) {
            if (!d[i]) {
                q[++tt] = i;
            }
        }
        
        while (hh <= tt) {
            int t = q[hh++];
            for (int i = h[t]; ~i; i = ne[i]) {
                int j = e[i];
                if (--d[j] == 0) {
                    q[++tt] = j;
                }
            }
        }
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        memset(h, -1, sizeof h);
        for (int i = 1; i <= m; ++i) {
            memset(st, 0, sizeof st);
            int cnt;
            scanf("%d", &cnt);
            int start = n, end = 1;
            while (cnt--) {
                int stop;
                scanf("%d", &stop);
                start = min(start, stop);
                end = max(end, stop);
                st[stop] = true;
            }
            
            int ver = n + i;
            for (int j = start; j <= end; ++j) {
                if (!st[j]) add(j, ver, 0);
                else add(ver, j, 1);
            }
        }
        
        topsort();
        
        for (int i = 1; i <= n; ++i) dist[i] = 1;
        for (int i = 0; i < n + m; ++i) {
            int j = q[i];
            for (int k = h[j]; ~k; k = ne[k]) {
                dist[e[k]] = max(dist[e[k]], dist[j] + w[k]);
            }
        }
        
        int res = 0;
        for (int i = 1; i <= n; ++i) res = max(res, dist[i]);
        
        printf("%d\n", res);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    3 参考

    acwing算法基础之搜索与图论–有向图的拓扑序列

  • 相关阅读:
    主流大语言模型的技术细节
    Leetcode 42.接雨水
    Curve 块存储应用实践 -- iSCSI
    05 正则表达式语法
    ClickHouse开发相关(UDAF)
    django rest framework serializer 增加自定义字段
    【C++】STL01-基本使用
    金仓数据库 KingbaseES PL/SQL 过程语言参考手册(8. PL/SQL动态SQL)
    Domino多瑙河EAP3以及Nomad Web 1.0.5
    C++ 智能指针深剖
  • 原文地址:https://blog.csdn.net/YMWM_/article/details/138051633