zoukankan      html  css  js  c++  java
  • 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
    0
    ");
                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
    %d
    ", res1, max(res1, res2));
        }
    
        return 0;
    }
    
  • 相关阅读:
    [转]Windows visio2019破解激活
    KMP模式匹配算法
    【蓝桥杯2016_C++】t3:方格填数
    【蓝桥杯2015_C++】t4:格子中输出
    【蓝桥杯2015_C++】t3:奇妙的数字
    【蓝桥杯2014_C++】t6:扑克序列
    【蓝桥杯2014_C++】t4:史丰收速算
    【蓝桥杯2014_C++】t3:神奇算式
    【蓝桥杯2017_C++】t1:迷宫
    【蓝桥杯】买不到的数目
  • 原文地址:https://www.cnblogs.com/YDDDD/p/11174471.html
Copyright © 2011-2022 走看看