POJ1236 Tarjan求强连通分量

题目链接:http://poj.org/problem?id=1236

题目大意:

有一个有向图,图中两点之间若有一条有向边代表一份软件可以从弧尾发送到弧头。

题目分两个小问,第一个问题事发送软件到图中的某些点,问最少发送多少个点可以使这份软件可以到达图中的任何一个点

第二小问问,最少向图中添加几条边可以使发送软件到图中任意一个点就可以使该软件到达图中的所有点。


思路:

求强联通分量,一个强联通分量可以当做一个点来看。第一问是求入度为0的点的数量,第二问求入度为0点的数量和出度为0的点的数量中的最大值。


#include
#include
#include

using namespace std;
const int N = 105;

struct Edge{
    int to, nx;
}e[N*N];

stack stk;
int dfn[N], low[N], sccn[N], sccCnt, step;
int tot, head[N];
bool instack[N];
int in[N], out[N];

void initMap(){
    memset(head, -1, sizeof(head));
    memset(in, 0, sizeof(in));
    memset(out, 0, sizeof(out));
    tot = 0;
}

void initScc(){
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    memset(sccn, 0, sizeof(sccn));
    memset(instack, false, sizeof(instack));
    step = 0;
}

void addEdge(int from, int to){
    e[++tot] = Edge{to, -1};
    e[tot].nx = head[from];
    head[from] = tot;
}

void tarjan(int u){
    stk.push(u);
    dfn[u] = low[u] = ++step;
    instack[u] = true;
    for (int k = head[u]; k != -1; k = e[k].nx){
        int to = e[k].to;
        if (!dfn[to]){
            tarjan(to);
            low[u] = min(low[u], low[to]);
        }
        else if (instack[to]){
            low[u] = min(low[u], dfn[to]);
        }
    }

    if (dfn[u] == low[u]){
        int v;
        sccCnt++;
        while(true){
            v = stk.top();
            stk.pop();
            instack[v] = false;
            sccn[v] = sccCnt;
            if (v == u) break;
        }
    }
}

void getScc(int n){
    initScc();
    for (int i = 1; i <= n; i++) if (!dfn[i]){
        tarjan(i);
    }
}


int main(){
    std::ios::sync_with_stdio(false);
    int n;
    while(cin >> n){
        initMap();
        for (int i = 1; i <= n; i++){
            int from, to;
            from = i;
            while(cin >> to && to){
                addEdge(from, to);
            }
        }

        initScc();
        getScc(n);
        for (int i = 1; i <= n; i++){
            for (int k = head[i]; k != -1; k = e[k].nx){
                int to = e[k].to;
                if (sccn[to] != sccn[i]){
                    in[sccn[to]]++;
                    out[sccn[i]]++;
                }
            }
        }

        if (sccCnt == 1){
            cout << "1" << endl;
            cout << "0" << endl;
            continue;
        }

        int ans1 = 0, ans2 = 0;
        for (int i = 1; i <= sccCnt; i++){
            if (!in[i]) ans1++;
            if (!out[i]) ans2++;
        }
        cout << ans1 << endl;
        cout << (ans1>ans2 ? ans1 : ans2) << endl;
    }
    return 0;
}



你可能感兴趣的:(算法学习,连通图)