zoukankan      html  css  js  c++  java
  • tarjan

    Tarjan

    有向图

    强连通分量

    void tarjan(int u) {
        dfn[u] = low[u] = ++times;
        stk[++top] = u;instk[u] = 1;
        for (int i  = h[u]; i != -1; i = ne[i]) {
            int v = to[i];
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if (instk[u]) low[u] = min(low[u], dfn[v]);
        }
        if (dfn[u] == low[u]) {
            ++scc_cnt;
            while (1) {
                int v = stk[top--];
                Size[scc_cnt] ++;
                id[v] = scc_cnt;
                instk[v] = 0;
                if (v == u)break;
            }
        }
    }
    

    2-sat问题

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    const int N = 2e6 + 9;
    const int M = 2e6 + 9;
    int h[N], ne[M], to[M], idx;
    void add(int u, int v) {
        ne[idx] = h[u], to[idx] = v, h[u] = idx++;
    }
    int dfn[N], low[N], times;
    int sz[N], id[N], scc_cnt;
    int stk[N], instk[N], top;
    
    void tarjan(int u) {
        dfn[u] = low[u] = times++;
        stk[++top] = u;
        instk[u]= 1;
        for (int i = h[u]; ~i; i = ne[i]) {
            int v = to[i];
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if (instk[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if (low[u] == dfn[u]){
            scc_cnt++;
            while (1) {
                int v = stk[top];
                top--;
                instk[v] = 0;
                id[v] = scc_cnt;
                sz[scc_cnt] ++;
                if (v == u)break;
            }
        }
    }
    int main() {
        int n, m;
        scanf("%d%d", &n, &m);
        memset(h, -1, sizeof h);idx = 0;
        for (int i = 1; i <= m; i ++) {
            int u, x, v, y;
            scanf("%d%d%d%d", &u, &x, &v, &y);
            add(u + (x^1)*n, v + y * n);//零代表v,1代表v+n,显然
            add(v + (y^1)*n, u + x * n);
        }
        for (int i = 1; i <= 2 * n; i ++) {
            if (!dfn[i]) tarjan(i);
        }
        for (int i = 1; i <= n; i ++) {
            if (id[i] == id[i + n]) {//在同一gcc无解
                puts("IMPOSSIBLE");
                return 0;
            }
        }
        puts("POSSIBLE");
        for (int i = 1; i <= n; i ++) {
            if (id[i] > id[i  + n])printf("1 ");//得到的topo序是反序,所以,越小越靠后,选后面的,又因为i+n是1,i是0
            else printf("0 ");
        }
    }
    

    无向图

    求割边(桥),求边双连通分量

    void tarjan(int u, int from) {
        dfn[u] = low[u] = ++times;
        stk[++top] = u;
        bool flag = 1;
        for (int i = h[u]; i != -1; i = ne[i])
        {
            int v = to[i];
            if ((i^1) == from && flag) {flag = 0;continue;}//重边
            if (!dfn[v]) {
                tarjan(v, i);
                low[u] = min(low[u], low[v]);
                if (low[v] > dfn[u]) {
                    ans++;//i和i^1是桥。
                }
            } else
                low[u] = min(low[u], dfn[v]);
        }
        if (low[u] == dfn[u]) {
            e_dcc++;
            while (1) {
                id[stk[top]] = e_dcc;
                if (stk[top--] == u)break;
            }
        }
    }
    

    求割点(割顶),求点双连通分量

    • 首先所求得的是一棵 (dfs) 树,然后在这棵树上,如果子树最低能达到的时间戳,即 (dfn[u] leq low[v]) 都到不了 (u) 上面的祖先,并且这个点 (u eq father) ,意思就是这个点 (u) 不是这个连通块随便找的最开始遍历的点,这样 (u) 是一个割点。

    • 如果 (u) 还是满足 (dfn[u] leq low[v]) 并且 (u) 有两个儿子,那么 (u) 是一个割点。

    void tarjan(int u, int fa) {
        dfn[u] = low[u] = ++times;
        stk[++top] = u;
        int cnt = 0;
        for (int i = h[u]; i != -1; i = ne[i])
        {
            int v = to[i];
            if (!dfn[v]) {
                tarjan(v, fa), ++cnt;
                low[u] = min(low[u], low[v]);
                if (low[v] >= dfn[u]) {
                    if (u != fa)cut[u] = 1;// 如果所有点到不了u上面去,那么显然 u是割点,
                    					 // 可是如果u是这个联通量第一个进来的元素,那么必然没有人会到u上面去
                    					 // 所以u != fa 
                    else cut[u] |= (cnt > 1); // 有两个儿子也行,所以是|=
                    ++dcc;
                    while (1) {
                        bl[stk[top]].push_back(dcc);//可以bl[dcc].push_back(stk[top]);
                        //主要是看自己需要啥,就咋写
                        sz[dcc]++;
                        if (stk[top--] == v)break;//这里确实有点不好理解,就是说,他这团是把当前这一团外面那一团给算上的,下次补一下图咕咕咕。
                    }
                    bl[u].push_back(dcc);
                    sz[dcc]++;
                }
            } else
                low[u] = min(low[u], dfn[v]);
        }
    }
    
  • 相关阅读:
    Flutter Card卡片布局
    Flutter Stack组件(安卓原生的帧布局)
    Flutter关于图片操作
    FlutterContainer组件、Text组件
    Flutter的第一次摸索
    Flutter入门,开始AndroidStuido写flutter
    Flutter之Dart语言入门
    Flutter 入门
    秋城图书馆
    Simpleperf分析之Android系统篇
  • 原文地址:https://www.cnblogs.com/Xiao-yan/p/14633093.html
Copyright © 2011-2022 走看看