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
  • 相关阅读:
    课堂作业04 2017.10.27
    课程作业 03 动手动脑 2017.10.20
    课程作业 03 2017.10.20
    HDU 3974 Assign the task
    POJ 2155 Matrix
    POJ 2481 Cows
    HDU 3038 How Many Answers Are Wrong
    CS Academy Array Removal
    POJ_1330 Nearest Common Ancestors LCA
    CF Round 427 D. Palindromic characteristics
  • 原文地址:https://www.cnblogs.com/DearDongchen/p/7514781.html
Copyright © 2011-2022 走看看