POJ1236-Network of Schools(Tarjan + 缩点)

题目链接


题意:给定一张有向图,问最少选择几个点能遍历全图,以及最少添加几条边使得有向图成为一个强连通图。

思路:对于有向图而言,首先求出有几个强连通分量,之后将每个强连通分量缩点,形成DAG,本题开头第一句就说图是连通的了。之后想要遍历整张图的话,只要找出入度为0的点有几个,而添加边的数量就取决于所有点的出入度大小。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

const int MAXN = 105;

vector<int> g[MAXN];
stack<int> s; 
int pre[MAXN], lowlink[MAXN], sccno[MAXN], dfs_clock, scc_cnt;
int n, in[MAXN], out[MAXN];

void tarjan(int u) {
    pre[u] = lowlink[u] = ++dfs_clock; 
    s.push(u);
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i]; 
        if (!pre[v]) {
            tarjan(v); 
            lowlink[u] = min(lowlink[u], lowlink[v]);
        }
        else if (!sccno[v])
            lowlink[u] = min(lowlink[u], pre[v]);
    }
    if (lowlink[u] == pre[u]) {
        scc_cnt++; 
        int x = -1;
        while (x != u) {
            x = s.top(); 
            s.pop();
            sccno[x] = scc_cnt;
        }
    }
}

void find_scc() {
    memset(pre, 0, sizeof(pre));
    memset(sccno, 0, sizeof(sccno));
    memset(lowlink, 0, sizeof(lowlink));
    dfs_clock = scc_cnt = 0;
    for (int i = 1; i <= n; i++)
        if (!pre[i])
            tarjan(i);
}

int main() {
    while (scanf("%d", &n) != EOF) {
        int u;
        for (int i = 1; i <= n; i++) {
            g[i].clear();
            while (scanf("%d", &u) && u) 
                g[i].push_back(u);
        }

        find_scc();
        if (scc_cnt == 1) {
            printf("1\n0\n"); 
            continue;
        }
        else {
            memset(in, 0, sizeof(in)); 
            memset(out, 0, sizeof(out)); 
            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]) {
                        in[sccno[v]]++;  
                        out[sccno[u]]++;
                    }
                }  
            } 
            int a = 0, b = 0;
            for (int i = 1; i <= scc_cnt; i++) {
                if (in[i] == 0) a++; 
                if (out[i]== 0) b++;  
            }
            int ans = max(a, b);
            printf("%d\n%d\n", a, ans);
        }
    } 
    return 0;
}


你可能感兴趣的:(POJ1236-Network of Schools(Tarjan + 缩点))