校園網絡(強連通分量)

校園網絡

時間限制:3000 ms  |  內存限制:65535 KB
難度:5
 
描述

南陽理工學院共有M個系,分別編號1~M,其中各個系之間達成有一定的協議,如果某繫有新軟件可用時,該系將允許一些其它的系複製並使用該軟件。但該允許關係是單向的,即:A系允許B系使用A的軟件時,B未必一定允許A使用B的軟件。

現在,請你寫一個程序,根據各個系之間達成的協議情況,計算出最少需要添加多少個兩系之間的這種允許關係,才能使任何一個繫有軟件使用的時候,其它所有系也都有軟件可用。

 
輸入
第一行輸入一個整數T,表示測試數據的組數(T<10)
每組測試數據的第一行是一個整數M,表示共有M個系(2<=M<=100)。
隨後的M行,每行都有一些整數,其中的第i行表示系i允許這幾個系複製並使用系i的軟件。每行結尾都是一個0,表示本行輸入結束。如果某個系不允許其它任何系使用該系軟件,則本行只有一個0.
輸出
對於每組測試數據,輸出最少需要添加的這種允許關係的個數。
樣例輸入
1
5
2 4 3 0
4 5 0
0
0
1 0
樣例輸出
2

 

      思路:

      強連通分量縮點後,再找入度爲0的節點數 和 出度爲0的節點數 的最大值即可。

 

      AC:

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

using namespace std;

const int VMAX = 105;

int in[VMAX], out[VMAX];
vector<int> G[VMAX];
int n;

int dfs_clock, scc_cnt;
int pre[VMAX], cmp[VMAX], low[VMAX];
stack<int> s;

void dfs (int u) {
    low[u] = pre[u] = ++dfs_clock;
    s.push(u);

    for (int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i];
        if (!pre[v]) {
            dfs(v);
            low[u] = min(low[u], low[v]);
        } else if (!cmp[v]) {
            low[u] = min(low[u], pre[v]);
        }
    }

    if (pre[u] == low[u]) {
        ++scc_cnt;
        for ( ;;) {
            int x = s.top(); s.pop();
            cmp[x] = scc_cnt;
            if (x == u) break;
        }
    }
}

void scc() {
    scc_cnt = dfs_clock = 0;
    memset(cmp, 0, sizeof(cmp));
    memset(pre, 0, sizeof(pre));

    for (int i = 1; i <= n; ++i) {
        if (!pre[i]) dfs(i);
    }
}

int main() {

    int t;
    scanf("%d", &t);

    while (t--) {
        scanf("%d", &n);

        for (int i = 1; i <= n; ++i) {
            G[i].clear();
            in[i] = out[i] = 0;
        }

        for (int i = 1; i <= n; ++i) {
            int num;
            while (~scanf("%d", &num) && num) {
                G[i].push_back(num);
            }
        }

        scc();

        for (int i = 1; i <= n; ++i) {
            for (int j = 0; j < G[i].size(); ++j) {
                int v = G[i][j];
                ++in[ cmp[v] ];
                ++out[ cmp[i] ];
            }
        }

        int in_num = 0, out_num = 0;
        for (int i = 1; i <= scc_cnt; ++i) {
            if (!in[i]) ++in_num;
            if (!out[i]) ++out_num;
        }

        printf("%d\n", max(in_num, out_num));
    }

    return 0;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章