HDOJ 2767 Proving Equivalences(强连通算法入门)

题意:

一个有向图,问至少添加几条边让整个图变成强连通图。

思路:

1. 基本上是模板题,首先对有向图进行缩点,即把所有强连通分量看成是一个点,Targan 算法 http://www.byvoid.com/blog/scc-tarjan/

2. 统计出度和入度为 0 的点的个数,输出其中的最大的一个即可。

 

#include <iostream>

#include <vector>

#include <stack>

#include <algorithm>

using namespace std;



const int MAXN = 20010;



vector<int> G[MAXN];

stack<int> S;

int dfn[MAXN], low[MAXN], sccno[MAXN], tclock, scccnt;

int indeg[MAXN], outdeg[MAXN];



void targan(int u) {

    dfn[u] = low[u] = ++tclock;

    S.push(u);



    for (int i = 0; i < G[u].size(); i++) {

        int v = G[u][i];

        if (!dfn[v]) {

            targan(v);

            low[u] = min(low[u], low[v]);

        } else if (!sccno[v]) {

            low[u] = min(low[u], dfn[v]);

        }

    }



    if (low[u] == dfn[u]) { 

        scccnt += 1;

        int v = -1;

        while (v != u) {

            v = S.top(); 

            S.pop();

            sccno[v] = scccnt;

        }

    }

}



void findscc(int n) {

    tclock = scccnt = 0;



    memset(sccno, 0, sizeof(int)*(n+1));

    memset(dfn, 0, sizeof(int)*(n+1));

    memset(low, 0, sizeof(int)*(n+1));



    for (int i = 1; i <= n; i++) 

        if (!dfn[i])  targan(i);

}



int workout(int n) {

    if (scccnt == 1) 

        return 0;



    memset(indeg, 0, sizeof(int)*(n+1));

    memset(outdeg, 0, sizeof(int)*(n+1));



    for (int u = 1; u <= n; u++) {

        for (int i = 0; i < G[u].size(); i++) {

            int v = G[u][i];

            if (sccno[u] != sccno[v]) {

                indeg[sccno[v]] += 1;

                outdeg[sccno[u]] += 1;

            }

        }

    }



    int c1 = 0, c2 = 0;

    for (int i = 1; i <= scccnt; i++) {

        if (indeg[i] == 0) c1 += 1;

        if (outdeg[i] == 0) c2 += 1;

    }



    return max(c1, c2);

}



int main() {

    int cases;

    scanf("%d", &cases);

    while (cases--) {

        int n, m;

        scanf("%d%d", &n, &m);

        for (int i = 1; i <= n; i++)

            G[i].clear();

        for (int i = 0; i < m; i++) {

            int u, v;

            scanf("%d%d", &u, &v);

            G[u].push_back(v);

        }

        findscc(n);

        printf("%d\n", workout(n));

    }

    return 0;

}

你可能感兴趣的:(val)