计蒜客 商业信息共享

有 N 个公司,从每个公司都能单向地向另外一个公司分享最新商业信息,因为他们之间有着某种合作,你需要解决两个问题:

  1. 现在有一个最新的商业信息,至少需要告诉多少个公司,使得所有的公司最终都能得到该信息。
  2. 在原有基础上,至少需要再让多少对公司建立这种合作,使任意一个公司获得某个最新商业信息后,经过若干次分享,所有的公司最终都能得到该信息。

输入格式

第一行输入一个整数 N (1N100)。

接下来 N行,每行若干个整数,表示第 ii 个公司可以向哪些公司分享信息,以 0 结束。

输出格式

输出共两行,每行一个整数,分别表示问题 1 和问题 2 的答案。

样例输入

6
0
6 0
2 0
2 0
3 1 0
0

样例输出

2
2
分析:先缩点,第一小问就是求有多少点的入度为0,第二小问怎么求呢?
显然要加边使原图变成一个强联通分量,一定要让图中的所有点的出度和入度都为0,每次我们可以连一条边从出度为0的到入度为0的,但是可能出度入度为0的点数量不相等,取个max就好了.
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <stack>

using namespace std;

int n, ru[110], chu[110], head[110], nextt[10000], to[10000], tot = 1, scc[110], num, dfs_clock, pre[110], low[110],map[110][110];
int ru1[110], chu1[110];

stack<int> s;

void add(int x, int y)
{
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

void tarjan(int u)
{
    pre[u] = low[u] = ++dfs_clock;
    s.push(u);
    for (int i = head[u]; i; i = nextt[i])
    {
        int v = to[i];
        if (!pre[v])
        {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else
            if (!scc[v])
                low[u] = min(low[u], pre[v]);
    }
    if (low[u] == pre[u])
    {
        num++;
        while (1)
        {
            int t = s.top();
            s.pop();
            scc[t] = num;
            if (t == u)
                break;
        }
    }
}

void lianbian(int x)
{
    for (int i = head[x]; i; i = nextt[i])
    {
        int v = to[i];
        if (scc[x] != scc[v] && !map[scc[x]][scc[v]])
        {
            map[scc[x]][scc[v]] = 1;
            chu1[scc[x]]++;
            ru1[scc[v]]++;
        }
    }
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        int x;
        while (scanf("%d", &x) && x != 0)
        {
            add(i, x);
            ru[x]++;
            chu[i]++;
        }
    }
    for (int i = 1; i <= n; i++)
        if (!scc[i])
            tarjan(i);
    for (int i = 1; i <= n; i++)
        lianbian(i);
    int ans = 0,rucnt = 0,chucnt = 0;
    for (int i = 1; i <= num; i++)
    {
        if (!ru1[i])
            ans++;
    }
    printf("%d
", ans);
    //printf("%d
", num);
    int cr = 0, cc = 0;
    for (int i = 1; i <= n; i++)
    {
        if (chu[i] == 0)
            cc++;
        if (ru[i] == 0)
            cr++;
    }
    printf("%d", max(cc, cr));

    return 0;
}
 
原文地址:https://www.cnblogs.com/zbtrs/p/7522403.html