Network of Schools

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台电脑之间能够通过有向边(u,v)从第u台电脑传输文件到第v台电脑。如果给第u台电脑投放

一个文件,那么这个文件就能通过有向边传输到第v台电脑上,给你N台电脑的连接情况。

那么问题来了:1、最少向这N台电脑中的几台电脑投放文件,就能使N台电脑都能接收到文件。

2、最少向这N台电脑构成的图中添加几条边,使只向一台电脑投放文件,就能够是N台电脑都

能接收到文件。


思路:

该图中的文件具有传递性。很快发现强连通的特征。对应图中的一个强连通分量,只要向其中的

一个点投放文件,那么这个强连通分量就都能收到文件。将这个强连通分量缩点变为DAG(有向

无环图)。这是解第一个问题的基础。

在有向无环图中,边变为了强连通分量之间的文件传输关系。意味这:只要一个强连通分量有入

边,那么就可以通过这个入边从另外一个分量中接收文件。但是,无环图意味着肯定存在没有入

度(入度为0)的强连通分量,这些强连通分量没有文件来源,所以要作为投放文件的位置。那么,

第一问就只需要计算出缩点后入度为0的强连通分量数目即可。

而第二个问题,把一个有向无环图转换为一个强连通分量。强连通分量的主要特征是:每个点的

入度和出度都不为0,那么计算出入度为0的点的个数SumIn和出度为0的点的个数SumOut,题

目就变为了:在入度为0的点和出出度为0的点之间最少加多少边。很明显的可以看出,答案就是

max(SumIn,SumOut)。


意思是看的博客的,一下是我的代码:本来一直错,原来是dfn[u]=low[u]=cnt++不对(上一道题这样就对了。。。)·我也不知道为什么反正dfn[u]=low[u]=cnt++改成dfn[u]=low[u]=++cnt就过了,难道进栈次序不能从第0开始标记?得从第1个进栈开始标记?{还有不理解找与u相连的点,当访问的点已经在栈里时dfn和low比较后取最小的作为low[u]是什么

这里解析的挺好,有时间好好看看

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#include<iostream>
#define N 110
#define M 11000
using namespace std;
stack<int >q;
vector<int >G[M];
int dfn[N],low[N],v[N],cnt,scnt,n,m,blong[N];
int in[N],out[N];
void init()
{
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(v,0,sizeof(v));
    while(!q.empty()){q.pop();}
    for(int i=0;i<N;i++)
      G[i].clear();
    cnt=scnt=0;
}
void tarjan(int u)
{
    q.push(u);
    dfn[u]=low[u]=++cnt;///????
    v[u]=1;
    for(int i=0;i<G[u].size();i++)
    {
         int c=G[u][i];
        if(!dfn[c])
        {
            tarjan(c);
            low[u]=min(low[u],low[c]);
        }
        else if(v[c]) low[u]=min(low[u],dfn[c]);///??????????
    }
    if(dfn[u]==low[u])
    {
       scnt++;
        while(!q.empty())
        {
            int c=q.top();
            q.pop();
            v[c]=0;
            blong[c]=scnt;//记录t点在哪个连通分量中
            if(u==c) break;
        }
    }
}
void solve()
{
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
}
int main()
{ int a;
    while(cin>>n)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            cin>>a;
            while(a)
            {
                G[i].push_back(a);
                cin>>a;
            }
        }
        solve();
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<G[i].size();j++)
            {
                int c=G[i][j];
                if(blong[i]!=blong[c])//I V 不再一个连通图中
                {
                    ++in[blong[c]]; //v所在的连通图的入度加1
                    ++out[blong[i]];//i所在的连通图的出度加1
                }
            }
        }
        int mx1=0,mx2=0;
        for(int i=1;i<=scnt;i++)
        {
            if(!in[i]) ++mx1;
            if(!out[i]) ++mx2;
        }
        if(scnt==1)
            cout << "1"<<endl<<"0"<<endl;
        else cout<<mx1<<endl<<max(mx1,mx2)<<endl;
    }
    return 0;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值