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;
}
posted @ 2013-04-09 16:13  kedebug  阅读(642)  评论(0编辑  收藏  举报