[USACO5.3]校园网Network of Schools

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

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

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

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

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

 

 

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

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

$$ f(x) = a+b $$

假设起点数为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\n",ans);
    printf("%d\n",scc_cnt == 1 ? 0 : max(ans,res));
    return 0;
}

 

上一篇:后缀数组


下一篇:C++ stack容器详解