zoukankan      html  css  js  c++  java
  • tarjan算法

    tarjan用来求有向图上强连通分量

    强连通分量就是图的一个子图,这个子图上任意两点都可以相互到达

    tarjan是基于dfs的算法,从一个点开始探索,dfn数组存每点探索的时间戳,low数组存每点下面能找到的最小的时间戳

    显然当一个点dfn==low时 这个点是一个强连通分量的根

    虽然是dfs不过没有回溯,每个点每个边只访问一次 复杂度O(n+m)

    https://nanti.jisuanke.com/t/16955

    前几天乌鲁木齐网络赛

    给一个有向图问最少添加几条边可以让图强连通

    其实每个强连通分量可以看成一个点(反正这里面每两个点可达)

    要整个图连通, 每个“点”都要有入度和出度,这时只需要遍历每条边

    如果边u->v连接了两个不同的分量,那就out[flag[u]]++,in[flag[v]]++,表示这两个联通分量一个有出度一个有入度

    u->v连接相同分量不用管

    最后对每个连通分量统计一下缺的出度入度,至少要补完这些出度入度,所以输出大的值

    #include<cstdio>
    #include<stack>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn = 1e4+7, maxm = 1e5+7;
    struct edge{
        int v, nxt;
        edge(){}
        edge(int v, int nxt):v(v), nxt(nxt){}
    }e[maxm];
    int head[maxn], ins[maxn], dfn[maxn], low[maxn], flag[maxn], cur, Index, cnt;
    int in[maxn], out[maxn], n, m;
    stack<int>S;
    void addedge(int u, int v){
        e[cur] = edge(v, head[u]);
        head[u] = cur++;
    }
    void tarjan(int u){
        dfn[u] = low[u] = Index++;
        ins[u] = 1;
        S.push(u);
        for(int i = head[u]; ~i; i = e[i].nxt){
            int v = e[i].v;
            if(dfn[v] == -1){
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if(ins[v]){
                low[u] = min(low[u], dfn[v]);
            }
        }
        if(low[u] == dfn[u]){
            cnt++;
            while(1){
                int tmp = S.top();
                S.pop();
                ins[tmp] = 0;
                flag[tmp] = cnt;
                if(tmp == u)
                    break;
            }
        }
    }
    void init(){
        memset(head, -1, sizeof(head));
        memset(ins, 0, sizeof(ins));
        memset(dfn, -1, sizeof(dfn));
        memset(low, -1, sizeof(low));
        memset(flag, 0, sizeof(flag));
        memset(in, 0, sizeof(in));
        memset(out, 0, sizeof(out));
        cur = Index = cnt = 0;
    }
    void work(){
        for(int i = 1; i <= n; i++){
            if(dfn[i] == -1)
                tarjan(i);
        }
        for(int i = 1; i <= n; i++){
            for(int j = head[i]; ~j; j = e[j].nxt){
                int v = e[j].v;
                if(flag[i] != flag[v]){
                    out[flag[i]]++;
                    in[flag[v]]++;
                }
            }
        }
        int lossin = 0, lossout = 0;
        for(int i = 1; i <= cnt; i++){
            if(!in[i])
                lossin++;
            if(!out[i])
                lossout++;
        }
        if(cnt == 1){
            puts("0");
        }
        else{
            printf("%d
    ", max(lossin, lossout));
        }
    }
    int main(){
        int t;
        scanf("%d", &t);
        while(t--){
            init();
            scanf("%d%d", &n, &m);
            while(m--){
                int u, v;
                scanf("%d%d", &u, &v);
                addedge(u, v);
            }
            work();
        }
        return 0;
    }
      
    搞图论是没有用的,转行做数学题了hh
  • 相关阅读:
    二分+RMQ/双端队列/尺取法 HDOJ 5289 Assignment
    思维题 HDOJ 5288 OO’s Sequence
    树形DP Codeforces Round #135 (Div. 2) D. Choosing Capital for Treeland
    最大流增广路(KM算法) HDOJ 1853 Cyclic Tour
    最大流增广路(KM算法) HDOJ 1533 Going Home
    最大流增广路(KM算法) HDOJ 2255 奔小康赚大钱
    Complete the Word CodeForces
    Gadgets for dollars and pounds CodeForces
    Vasya and Basketball CodeForces
    Carries SCU
  • 原文地址:https://www.cnblogs.com/DearDongchen/p/7514781.html
Copyright © 2011-2022 走看看