有向图判环+判连通性

有向图求拓扑序

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

有向图判环

例题:
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

posted @   糖豆爸爸  阅读(94)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2018-05-16 Python3.6安装OpenCV
2018-05-16 CAS单点登录安装笔记
2018-05-16 pycharm+PyQt5+python最新开发环境配置
Live2D
点击右上角即可分享
微信分享提示