校园网络

题目

描述 Description
一些学校连入一个电脑网络。那些学校已订立了协议:每个学校都会给其它的一些学校分发软件(称作“接受学校”)。注意如果 B 在 A 学校的分发列表中,那么 A 不必也在 B 学校的列表中。
你要写一个程序计算,根据协议,为了让网络中所有的学校都用上新软件,必须接受新软件副本的最少学校数目(子任务 A)。更进一步,我们想要确定通过给任意一个学校发送新软件,这个软件就会分发到网络中的所有学校。为了完成这个任务,我们可能必须扩展接收学校列表,使其加入新成员。计算最少需要增加几个扩展,使得不论我们给哪个学校发送新软件,它都会到达其余所有的学校(子任务 B)。一个扩展就是在一个学校的接收学校列表中引入一个新成员。
输入格式 Input Format
第一行包括一个整数 N:网络中的学校数目(2 <= N <= 100)。学校用前 N 个正整数标识。接下来 N 行中每行都表示一个接收学校列表(分发列表)。第 i+1 行包括学校 i 的接收学校的标识符。每个列表用 0 结束。空列表只用一个 0 表示。
输出格式 Output Format
第一行应该包括一个正整数:子任务 A 的解。第二行应该包括子任务 B 的解。
样例输入 Sample Input
5
2 4 3 0
4 5 0
0
0
1 0
样例输出 Sample Output
1
2
时间限制 Time Limitation
1s

题解

tarjan缩点
任务A:
需要求最多在多少学校发送新软件,其实就是求缩点后入度为0的个数(如果入度不为0就可以从其他学校传过来)
任务B:
求入度为0的点数与出度为0的点的较大值。

code

#include 
#define fup(i, a, b) for(int i = a; i <= b; ++i) 
#define fdown(i, a, b) for(int i = a; i >= b; --i)
#define pri_(k) printf("%d ", k)
#define pri(k) printf("----%d---\n", k)
const int maxn = 5e5 + 100;
const int inf = 0x3f3f3f3f;
typedef long long ull;

namespace millope {
    inline int kswap(int &a, int &b) { a ^= b ^= a ^= b; }
    inline int kmin(int a, int b) { return a > b ? b : a; }
    inline int kmax(int a, int b) { return a > b ? a : b; }
    inline int read() {
        int s = 0, w = 1;
        char ch = getchar();
        while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
        while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
        return s * w;
    }
}
using namespace millope;
using namespace std;

int n;
int sum = 0;
int tot = 0;
int cnt = 0;
int tim = 0;
int ans1 = 0;
int ans2 = 0;
int in[maxn];
int out[maxn];
int dfn[maxn];
int low[maxn];
int col[maxn];
int sig[maxn][5];
int link[maxn];
int vis[maxn];
stack<int> sta;
struct Edge { 
    int next, to;
    Edge() {
        next = 0, to = 0;
    } 
} e[maxn];

inline void add(int from, int to) {
    e[++tot].to = to;
    e[tot].next = link[from];
    link[from] = tot;
}

void tarjan(int x) {
    dfn[x] = low[x] = ++tim;
    sta.push(x);
    vis[x] = 1;
    for (int i = link[x]; i; i = e[i].next) {
        int v = e[i].to;
        if(vis[v] == 0) {
            tarjan(v);
            low[x] = min(low[x], low[v]);
        }
        else if (vis[v] == 1) {
            low[x] = min(low[x], dfn[v]);
        }
    }
    int temp;
    if (low[x] == dfn[x]) {
        ++sum;
        do {
        	temp = sta.top();
            sta.pop();
            col[temp] = sum;
            vis[temp] = -1;
        }while (temp != x);
    }
    return ;
}

int main() {
	memset(link, 0, sizeof(link));
	memset(dfn, 0, sizeof(dfn));
	memset(low, 0, sizeof(low));
	memset(vis, 0, sizeof(vis));
    n = read();
    for (int i = 1; i <= n; ++i) {
        while (true) {
            int x = read();
            if (!x) break;
            sig[++cnt][1] = i;
            sig[cnt][2] = x;
            add(i, x);
        }
    }
    for (int i = 1; i <= n; ++i) {
        if (!vis[i]) tarjan(i);
    }
    for (int i = 1; i <= cnt; ++i) {
        if (col[ sig[i][1] ] != col[ sig[i][2] ] ) {
            in[ col[ sig[i][2] ] ]++;
            out[ col[ sig[i][1] ] ]++;
        }
    }
	ans1 = 0, ans2 = 0;
    for (int i = 1; i <= sum; ++i) {
        if (in[i] == 0) ++ans1;
        if (out[i] == 0) ++ans2;
    }
    if (sum == 1) printf("1\n0\n");
    else printf("%d\n%d\n", ans1, kmax(ans1, ans2));
    return 0;
}

你可能感兴趣的:(题解————题解)