POJ-1236-Network of Schools

链接:

https://vjudge.net/problem/POJ-1236

题意:

一些学校连接到了一个计算机网络。网络中的学校间有如下约定:每个学校维护一个列表,当该学校收到软件或信息后将会转发给列表中的所有学校(也就是接收方列表)。需要注意的是如果B学校在A学校的接收方列表中,A学校不一定会出现在B学校的接收方列表中。
你现在的任务是写出一个程序来计算必须收到一份软件来使网络中的所有学校都能收到软件的学校的数量的最小值(此为子任务A)。作为一个远期目标,我们希望给任意一个学校发送一份软件都能使网络中的所有学校都收到软件。为了实现这个目标,我们或许需要在一些学校的接收方列表中添加新项。 你现在需要计算出至少需要添加多少新项才能实现这个远期目标(此为子任务B)。

思路:

最少的学校接受就是整个有向图缩点为一个有向无环图DAG。求DAG上入度为0的点有多少。
而求添加新项,就是求DAG增加最少的边使其强连通。而增加的最少边就是max(入度为0, 出度为0)。
因为使DAG强连通,使每个点都有入度和出度,同时给一个点增加入度的同时,可以给一个点增加出度,反过来同理。

代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <memory.h>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <stack>
using namespace std;
const int MAXN = 1e2+10;
const int INF = 1<<30;

vector<int> G[MAXN];
stack<int> St;
int Vis[MAXN];
int Dfn[MAXN], Low[MAXN];
int Fa[MAXN], Dis_in[MAXN], Dis_out[MAXN];
int n, times, cnt;
int sum;

void Tarjan(int x)
{
    Dfn[x] = Low[x] = ++times;
    Vis[x] = 1;
    St.push(x);
    for (int i = 0;i < G[x].size();i++)
    {
        int nextnode = G[x][i];
        if (Dfn[nextnode] == 0)
        {
            Tarjan(nextnode);
            Low[x] = min(Low[x], Low[nextnode]);
        }
        else if (Vis[nextnode])
            Low[x] = min(Low[x], Dfn[nextnode]);
    }
    if (Dfn[x] == Low[x])
    {
        cnt++;
        while (St.top() != x)
        {
            Fa[St.top()] = cnt;
            Vis[St.top()] = 0;
            St.pop();
        }
        Fa[St.top()] = cnt;
        Vis[St.top()] = 0;
        St.pop();
    }
}

void Init()
{
    for (int i = 1;i <= n;i++)
        G[i].clear(), Fa[i] = i;
    cnt = times = 0;
    while (!St.empty())
        St.pop();
}

int main()
{
    while(~scanf("%d", &n))
    {
        Init();
        for (int i = 1; i <= n; i++)
        {
            int u;
            while (~scanf("%d", &u) && u)
                G[i].push_back(u);
        }
        for (int i = 1;i <= n;i++)
        {
            if (Dfn[i] == 0)
                Tarjan(i);
        }
        if (cnt == 1)
        {
            printf("1\n0\n");
            continue;
        }
        for (int i = 1;i <= n;i++)
        {
            for (int j = 0;j < G[i].size();j++)
            {
                int node = G[i][j];
                if (Fa[i] != Fa[node])
                {
                    Dis_in[Fa[node]]++;
                    Dis_out[Fa[i]]++;
                }
            }
        }
        int res1 = 0, res2 = 0;
        for (int i = 1;i <= cnt;i++)
            if (Dis_in[i] == 0)
                res1++;
            else if (Dis_out[i] == 0)
                res2++;
        printf("%d\n%d\n", res1, max(res1, res2));
    }

    return 0;
}
posted @ 2019-07-12 10:19  YDDDD  阅读(134)  评论(0编辑  收藏  举报