POJ - 1236 -- Network of Schools

版权声明: https://blog.csdn.net/moon_sky1999/article/details/81539741

题目来源:http://poj.org/problem?id=1236

最开始做的时候理解错题意了QWQ,WA了几发。

题目大意:

给定一个有向图,第一问是选择部分的节点,以这些节点为起点可以遍历整个图,最少要选几个节点。

第二问是问添加最少多少条边,使得以任意节点为起点,均可以遍历整个图。

思路:

先用tarjan求出整个图的所有强连通分量,对每个连通分量进行缩点,处理出缩点后的图。

第一问即是找出缩点后的图中所有入度为0的点。

第二问是添加最少多少条边让这个图变为强连通图。也就是max{入度为0的点,出度为0的点}。(首尾相连)

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#define ll long long
using namespace std;
int n, cur, top, color, dfn[111], s[111], low[111], c[111], num[111], du[111], dd[111];
bool g[111][111], vis[111], e[111][111];
void tarjan(int u) {
    dfn[u] = low[u] = ++cur;
    vis[u] = 1;
    s[++top] = u;
    for (int i = 1; i <= n; ++i) {
        if (g[u][i]) {
            if (dfn[i] == 0)tarjan(i);
            if (vis[i] && low[u] > low[i])low[u] = low[i];
        }
    }
    if (dfn[u] == low[u]) {
        color++;
        while (s[top + 1] != u) {
            vis[s[top]] = 0;
            c[s[top]] = color;
            num[color]++;
            top--;
        }
    }
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    while (cin >> n) {
        int x;
        memset(g, 0, sizeof(g));
        memset(c, 0, sizeof(c));
        memset(num, 0, sizeof(num));
        memset(s, 0, sizeof(s));
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(vis, 0, sizeof(vis));
        memset(du, 0, sizeof(du));
        memset(dd, 0, sizeof(dd));
        for (int i = 1; i <= n; ++i) {
            while (cin >> x) {
                if (x == 0)break;
                g[i][x] = 1;
            }
        }
        cur = top = color = 0;
        for (int i = 1; i <= n; ++i) {
            if (dfn[i] == 0) {
                tarjan(i);
            }
        }
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (g[i][j] && c[i] != c[j]) {
                    e[c[i]][c[j]] = 1;
                }
            }
        }
        for (int i = 1; i <= color; ++i) {
            for (int j = 1; j <= color; ++j) {
                if (e[i][j]) {
                    du[j]++;
                    dd[i]++;
                }
            }
        }
        int ans = 0, tot = 0;
        for (int i = 1; i <= color; ++i) {
            if (du[i] == 0)
                ans++;
        }
        cout << ans << endl;
        for (int i = 1; i <= color; ++i) {
            if (dd[i] == 0)
                tot++;
        }
        if (color == 1)cout << 0 << endl;
        else cout << max(tot, ans) << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/moon_sky1999/article/details/81539741
今日推荐