zoukankan      html  css  js  c++  java
  • [USACO5.3]校园网Network of Schools

    一些学校连入一个电脑网络。那些学校已订立了协议:每个学校都会给其它的一些学校分发软件(称作“接受学校”)。

    注意即使 B 在 A学校的分发列表中,也不一定在 B 学校的列表中。

    你要写一个程序计算,根据协议,为了让网络中所有的学校都用上新软件,必须接受新软件副本的最少学校数目(子任务 A)。

    更进一步,我们想要确定通过给任意一个学校发送新软件,这个软件就会分发到网络中的所有学校。为了完成这个任务,我们

    可能必须扩展接收学校列表,使其加入新成员。计算最少需要增加几个扩展,使得不论我们给哪个学校发送新软件,它都会到达其余所有的学校(子任务 B)。一个扩展就是在一个学校的接收学校列表中引入一个新成员。

    一个强联通分量的模板题 首先第一问的答案显然是缩点后出度为零的点的个数(起点);

    第二问答案可以大胆猜测 得到其为 max(起点数加终点数)

    假设起点数为P,终点数为Q 且P <= Q,那么我们只需要找到一个最长的起点并把各个终点向它连边即可,Q <= P 同理可得

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    int n;
    const int N = 110;
    const int M = 10010;
    int h[N],e[M],ne[M],idx = 0;
    int low[N],dfn[N],id[N],din[N],dout[N];
    int timestamp = 0,scc_cnt = 0;
    bool is_stk[N];
    int tot = 0,stk[N];
    
    void add(int u,int v)
    {
        e[idx] = v;
        ne[idx] = h[u];
        h[u] = idx ++;
    }
    
    void tarjan(int u)
    {
        low[u] = dfn[u] = ++ timestamp;
        stk[++ tot] = u;
        is_stk[u] = true;
        for(int i = h[u]; ~i; i = ne[i])
        {
            int j = e[i];
            if(!dfn[j])
            {
                tarjan(j);
                low[u] = min(low[u],low[j]);
            }
            else if(is_stk[j]) low[u] = min(low[u],dfn[j]);
        }
    
        if(low[u] == dfn[u])
        {
            int y;
            scc_cnt ++;
            do
            {
                y = stk[tot --];
                is_stk[y] = false;
                id[y] = scc_cnt;
    
            } while (y != u);
            
        }
    }
    
    int main()
    {
        memset(h,-1,sizeof h);
        scanf("%d",&n);
        for(register int i = 1; i <= n; ++ i)
        {
            int x;
            while(cin >> x,x)
            {
                add(i,x);
            }
        }
        for(register int i = 1; i <= n; ++ i)
            if(!dfn[i]) tarjan(i);
         for (int i = 1; i <= n; i ++ )
            for (int j = h[i]; ~j; j = ne[j])
            {
                int k = e[j];
                int a = id[i], b = id[k];
                if (a != b) dout[a] ++,din[b] ++;
            }
        int ans = 0,res = 0;
        for(register int i = 1; i <= scc_cnt; ++ i)
        {
            if(!din[i]) ans ++;
            if(!dout[i]) res ++;
    
        }
        printf("%d
    ",ans);
        printf("%d
    ",scc_cnt == 1 ? 0 : max(ans,res));
        return 0;
    }
  • 相关阅读:
    如何在文本编辑器中实现搜索功能? 字符串比较算法 BF算法 RK算法
    怎么读源码 读源码的一些技巧
    系统性学习
    堆 二叉堆 找流的中位数
    apk系统签名小技巧
    常用adb命令总结
    Android6.0 源码修改之Setting列表配置项动态添加和静态添加
    AndroidStudio开发Java工程(解决java控制台中文打印乱码+导入jar包运行工程)
    加载loading对话框的功能(不退出沉浸式效果)
    Android6.0 源码修改之屏蔽导航栏虚拟按键(Home和RecentAPP)/动态显示和隐藏NavigationBar
  • 原文地址:https://www.cnblogs.com/yjyl0098/p/15375102.html
Copyright © 2011-2022 走看看