• POJ 1236 Network of Schools(强连通分量缩点求根节点和叶子节点的个数)


    Description:

    A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distribution list of school A, then A does not necessarily appear in the list of school B 
    You are to write a program that computes the minimal number of schools that must receive a copy of the new software in order for the software to reach all schools in the network according to the agreement (Subtask A). As a further task, we want to ensure that by sending the copy of new software to an arbitrary school, this software will reach all schools in the network. To achieve this goal we may have to extend the lists of receivers by new members. Compute the minimal number of extensions that have to be made so that whatever school we send the new software to, it will reach all other schools (Subtask B). One extension means introducing one new member into the list of receivers of one school. 

    Input:

    The first line contains an integer N: the number of schools in the network (2 <= N <= 100). The schools are identified by the first N positive integers. Each of the next N lines describes a list of receivers. The line i+1 contains the identifiers of the receivers of school i. Each list ends with a 0. An empty list contains a 0 alone in the line.

    Output:

    Your program should write two lines to the standard output. The first line should contain one positive integer: the solution of subtask A. The second line should contain the solution of subtask B.

    Sample Input:

    5
    2 4 3 0
    4 5 0
    0
    0
    1 0
    

    Sample Output:

      1

      2


    题意:有n所学校,它们的网络可能不是完全连通的,现在要传送软件,有可能一份软件不能让每个学校都能接收到
    问题A:求出需要几份软件才能让每个学校都能接受到,即求出入度为0的点的个数(根节点个数)
    问题B:求出需要再增加几次网络连接才能只需要一份软件不管从哪发,每个学校都能收到,这里需要求出度为0的个数(叶子节点个数)

    总之这道题的A就是为了求出根节点的个数,而问题B就是为了求出根节点个数和叶子节点个数更大的那个

    (假设根节点有n个,叶子节点有m个)加边的时候可以考虑:t = min(n, m), 先将t个根节点和t个叶子节点连接,然后再将多出的部分连接到其他节点上

    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #include<vector>
    #define N 110
    using namespace std;
    int dfn[N], low[N], Stack[N], vis[N];
    int be[N], In[N], Out[N], Map[N][N]; //be数组存放该点属于哪一个强连通分量
    int Time, top, ans, in, out, n;      //In数组存放入度的值,用于判断该点入度是否为0,即该点是否为根节点(没有点可以到达它)
    vector<vector<int> >G;               //Out数组存放出度的值,用于判断该点出度是否为0,即该点是否为叶子节点(它不能到达任何点)
    void Init()                          //in表示入度为0,即根节点的个数
    {                                    //out表示出度为0,即叶子节点的个数
        G.clear();
        G.resize(n+1);
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(vis, 0, sizeof(vis));
        memset(In, 0, sizeof(In));
        memset(Out, 0, sizeof(Out));
        memset(be, 0, sizeof(be));
        memset(Map, 0, sizeof(Map));
        Time = top = in = out = ans = 0;
    }
    void Tarjan(int u)
    {
        int i, len, v;
        dfn[u] = low[u] = ++Time;
        Stack[top++] = u;
        vis[u] = 1;
        len = G[u].size();
        for (i = 0; i < len; i++)
        {
            v = G[u][i];
            if (!dfn[v])
            {
                Tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if (vis[v]) low[u] = min(low[u], dfn[v]);
        }
        if (dfn[u] == low[u])
        {
            do
            {
                v = Stack[--top];
                be[v] = ans; //记录该点属于哪一个强连通分量,便于重新构图
                vis[v] = 0;
            }while(u != v);
            ans++; //连通分量的个数
        }
    }
    int main ()
    {
        int i, b, len, v, j;
        while (scanf("%d", &n) != EOF)
        {
            Init();
            for (i = 1; i <= n; i++)
            {
                while (scanf("%d", &b), b)
                    G[i].push_back(b);
            }
            for (i = 1; i <= n; i++)
                if (!dfn[i]) Tarjan(i); 
            for (i = 1; i <= n; i++)
            {
                len = G[i].size();
                for (j = 0; j < len; j++)
                {
                    v = G[i][j];
                    Map[be[i]][be[v]] = 1; //重新构图,将每个强连通分量变为新的节点,表示be[i]可以到达be[v]
                }
            }
            for (i = 0; i < ans; i++)
            {
                for (j = 0; j < ans; j++)
                {
                    if (i == j) continue; //自己肯定能到达自己,跳过
                    else if (Map[i][j]) //当i可以到达j时,表示j肯定不是根节点,i肯定不是叶子节点,为了标记让其值++
                    {
                        In[j]++; 
                        Out[i]++;
                    }
                }
            }
            for (i = 0; i < ans; i++)
            {
                if (!In[i]) in++; //只有当入度为0是才是根节点,记录根节点个数
                if (!Out[i]) out++; //只有当出度为0是才是叶子节点,记录叶子节点个数
            }
            printf("%d
    ", in);
            if (ans == 1) printf("0
    "); //如果本来就只有1个强连通分量,则不需要再添加任何边
            else printf("%d
    ", max(in, out));
        }
        return 0;
    }
  • 相关阅读:
    day003|python基础回顾3
    14Linux之网络管理
    13Linux之磁盘管理
    12Linux之进程管理
    11Linux之软件包管理
    10Linux之用户权限管理
    09Linux之文件管理
    08Linux之目录结构
    07Linux之bash解释器交互式环境特性
    06Linux之shell介绍
  • 原文地址:https://www.cnblogs.com/syhandll/p/4708587.html
Copyright © 2020-2023  润新知