• 有向图判环+判连通性


    有向图求拓扑序

    • 求拓扑序有\(dfs\)\(bfs\)两种方法。
    • 在求拓扑序过程中,可以增加判断是否有环的代码。
    • 有些题目中,单独采用\(bfs\)\(dfs\)只为了判断是否有环,而不是要输出拓扑序,这时代码可以适当简化。

    有向图判环

    例题:
    \(HDU\) \(3342\) \(Legal\) \(or\) \(Not\)

    1、\(bfs\)判环

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e3 + 10, M = N << 1;
    int ind[N];
    int n, m;
    //邻接表
    int e[M], h[N], idx, ne[M];
    void add(int a, int b) {
        e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }
    int q[N];
    int main() {
        while (~scanf("%d %d", &n, &m) && n) {
            memset(ind, 0, sizeof(ind));
            memset(h, -1, sizeof h);
            idx = 0;
    
            for (int i = 1; i <= m; i++) {
                int a, b;
                scanf("%d %d", &a, &b);
                add(a, b);
                ind[b]++; //记录入度
            }
            int hh = 0, tt = -1;
            for (int i = 0; i < n; i++)
                if (ind[i] == 0) q[++tt] = i; //入度为0的入队列
    
            while (hh <= tt) {
                int u = q[hh++];
                for (int i = h[u]; ~i; i = ne[i]) {
                    int j = e[i];
                    ind[j]--;                     //拓扑模拟减去边,入度-1
                    if (ind[j] == 0) q[++tt] = j; //如果入度为0,则此节点入队列
                }
            }
            //检查入过队列的节点个数是不是n个,相等则无环
            hh == n ? puts("YES") : puts("NO");
        }
        return 0;
    }
    

    2、\(dfs\)判环

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 110, M = N << 1;
    
    //邻接表
    int e[M], h[N], idx, ne[M];
    void add(int a, int b) {
        e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }
    
    int color[N]; // 染色法数组: 0:还没有访问过 1:正在访问中 2:它及它的子节点都已经访问过
    int n, m;     // n个顶点,m条边
    
    bool dfs(int u) {
        color[u] = 1;
        for (int i = h[u]; ~i; i = ne[i]) {
            int j = e[i];
            if (color[j] == 1) return true;
            if (color[j] == 0 && dfs(j)) return true;
        }
        color[u] = 2;
        return false;
    }
    
    int main() {
        while (~scanf("%d%d", &n, &m) && n) {
            memset(h, -1, sizeof(h));        //多组测试数据,每次输入清空地图
            memset(color, 0, sizeof(color)); //多组测试数据,每次输入清空染色法数组
            idx = 0;
    
            for (int i = 1; i <= m; i++) { //有向图,m条边
                int a, b;
                scanf("%d%d", &a, &b);
                add(a, b);
            }
    
            //是不是有环
            bool flag = false;
            // 因为本题的节点号是从0开始的
            for (int i = 0; i < n; i++) { //枚举每个顶点,注意顶点号从0开始,至n-1止。
                if (!color[i]) {
                    flag = dfs(i); //如果当前节点的颜色标识是0,表示还没有访问过,需要继续深搜,
                    if (flag) break;
                }
            }
    
            !flag ? puts("YES") : puts("NO");
        }
        return 0;
    }
    

    3、强连通分量判环

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e2 + 10, M = N << 1;
    //邻接表
    int e[M], h[N], idx, ne[M];
    void add(int a, int b) {
        e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }
    
    int low[N], dfn[N], stk[N];
    int timestamp, top;
    int scc;
    bool in_stk[N];
    void tarjan(int u) {
        dfn[u] = low[u] = ++timestamp;
        stk[++top] = u;
        in_stk[u] = true;
        for (int i = h[u]; ~i; i = ne[i]) {
            int j = e[i];
            if (!dfn[j]) {
                tarjan(j);
                low[u] = min(low[u], low[j]);
            } else if (in_stk[j])
                low[u] = min(low[u], low[j]);
        }
        if (dfn[u] == low[u]) {
            ++scc;
            int x;
            do {
                x = stk[top--];
                in_stk[x] = false;
            } while (x != u);
        }
    }
    
    int main() {
        int n, m;
        while (~scanf("%d%d", &n, &m) && n) {
            idx = 0;
            memset(h, -1, sizeof(h));
            while (m--) {
                int a, b;
                scanf("%d%d", &a, &b);
                add(a, b);
            }
            //初始化
            timestamp = scc = top = 0;
            memset(in_stk, false, sizeof(in_stk));
            memset(dfn, 0, sizeof(dfn));
    
            for (int i = 0; i < n; i++)
                if (!dfn[i]) tarjan(i);
            //强连通分量数量等于节点数,说明无环,并且是一个连通图
            scc == n ? puts("YES") : puts("NO");
        }
        return 0;
    }
    

    拓扑序的应用

    https://www.jianshu.com/p/1cda977685b6

  • 相关阅读:
    pandas缺失值处理之——如何消去Nan值对数字型字符串数据类型的影响,让数字型字符串保持原始str类型,而不会自动变为float类型?
    pandas基础操作
    pandas基础操作一
    Selenium — 点击被页面上其他元素遮住的控件
    Selenium中,若HTML元素输入框带有readonly属性,如何实现修改其元素内容
    Newman + Jenkins 实现postman持续集成
    on java 8 第十四章 流式编程
    on java 8 第十三章 函数式编程
    Thinking in java Chapter20 annotations
    Thinking in java Chapter21 并发
  • 原文地址:https://www.cnblogs.com/littlehb/p/16277800.html
Copyright © 2020-2023  润新知