POJ 1236 Network of Schools【强连通Kosaraju+缩点+思维】

来源:互联网 发布:机械能守恒实验带数据 编辑:程序博客网 时间:2024/05/18 03:53

Network of Schools

Time Limit: 1000MS

 

Memory Limit: 10000K

Total Submissions: 15028

 

Accepted: 5984

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

Source

IOI 1996

 

题目大意:有向关系体现在电脑可以通过网络单向的传输文件,并规定一旦有电脑存在该文件,那么所有它能传输的电脑就能在第一时间得到这个文件,题目有两个问题,第一个是最少向网络中的几台电脑投放文件,能使得整个图中的电脑都得到文件,第二个问题是要最少再连接几条边,使得任意向图中一点投放文件,其他所有电脑都能得到文件。


思路:

1、首先对于第一个问题,如果有这样一个图:


不难分析出,如果对节点1和节点5投放文件,那么就能使得整个图都得到文件,并且投放的文件数最少。那么我们不妨来分析一下节点1和节点5有什么特点,值得我们投入关注于这两个点上,首先对于有向图 ,有出度入度的定义,其中:
1的出度为2,入度为0,

2的出度为1,入度为1,

3的出度为0,入度为1.

4的出度为0,入度为2,

5的出度为4,入度为0,

我们不难看出,节点1和节点5让我们投于极大关注的一个重要原因是其入度为0,我们知道,一个点的入度如果为0,那么我们一定要向其投放文件,相对的,如果所有入度为0的点都投向了文件,那么其他入度不为0的点,一定会从其他节点传输过来文件,所以对于第一问:

找到度为0的节点总数,就是答案


2、对于第二个问题,hdu上有两个这样的题大家也可以去做做看。hdu 3836 hdu 2767

我们首先来观察一个强连通分量为1的图【注意看箭头方向】:

图1:


对于有向边,我们有入度和出度的定义。在上图中,每个节点的入度和出度都是1.也同时说明,对于一个强连通分量为1的图,出度和入度两种度中,一定两种度都没有0度的存在。我们不妨在观察一个强连通分量为1的图:


其1的出度:2,入度2。

其2的出度:1,入度1。

其3的出度:1,入度1.

我们再观察一个强连通分量不是1的图:


其1的出度为2,入度为0

其2的出度为0,入度为1

其3的出度为0,入度为1

那么我们要将这个图变成强连通分量为1的图,我们不妨这样考虑:既然强连通分量为1的图有这样的特点:如果一个图是强连通分量为1的图,对于每个节点来说,一定没有任何一个点的出度或者入度有0的情况。那么我们的任务也就明确了,对于所有节点度的处理,使得没有0度的存在。

那么我们对上图再进行分析,这里设出度为0的节点数为a,设入度为0的节点数为b,其实我们如果找到了a和b的值,搞定最大值,其实也就搞定了这个问题。


那么最终得到这样的结论:设定output=max(a,b),假设output=a,那么就对出度为0的节点,一共连a条边,这些边都从出度为0的节点出发,到应该到的地方去。最终一定能使得图的出度和入度没有度为0的节点存在,同理,如果output=b,也能够达成目标。


3、既然得到了结论,下一个动作就是做题啦~,因为图是会存在有向环的,所以我们使用Kosaraju算法来求出强连通分量,然后对所有属于一个强连通分量的点缩点看成一个点进行染色,然后统计入度出度,得到结果。


AC代码:

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int head[105];int head2[105];struct EdgeNode{    int from;    int to;    int next;}e[300000],ee[300000];int n,m,cont,cont2,sig;int in[105];int out[105];int vis[105];int num[105];int color[105];void add(int from,int to){    e[cont].from=from;    e[cont].to=to;    e[cont].next=head[from];    head[from]=cont++;}void add2(int from,int to){    ee[cont2].from=from;    ee[cont2].to=to;    ee[cont2].next=head2[from];    head2[from]=cont2++;}void init(){    cont=0;    cont2=0;    memset(vis,0,sizeof(vis));    memset(out,0,sizeof(out));    memset(in,0,sizeof(in));    memset(head,-1,sizeof(head));    memset(head2,-1,sizeof(head2));    memset(color,0,sizeof(color));    memset(num,0,sizeof(num));}void Dfs(int u){    vis[u]=1;    for(int i=head[u];i!=-1;i=e[i].next)    {        int v=e[i].to;        if(vis[v]==0)        {            Dfs(v);        }    }    num[sig++]=u;}void Dfs2(int u){    vis[u]=1;    color[u]=sig;    for(int i=head2[u];i!=-1;i=ee[i].next)    {        int v=ee[i].to;        if(vis[v]==0)        {            Dfs2(v);        }    }}void Kosaraju(){    sig=1;    memset(vis,0,sizeof(vis));    for(int i=1;i<=n;i++)    {        if(vis[i]==0)        {            Dfs(i);        }    }    sig=0;    memset(vis,0,sizeof(vis));    for(int i=n;i>=1;i--)    {        if(vis[num[i]]==0)        {            sig++;            Dfs2(num[i]);        }    }    if(sig==1)    {        printf("1\n0\n");        return ;    }    for(int i=1;i<=n;i++)    {        for(int k=head[i];k!=-1;k=e[k].next)        {            int u=i,v=e[k].to;            if(color[u]!=color[v])            {                out[color[u]]++;                in[color[v]]++;            }        }    }    int ruu=0;    int chu=0;    for(int i=1;i<=sig;i++)    {        if(in[i]==0)ruu++;        if(out[i]==0)chu++;    }    printf("%d\n",ruu);    printf("%d\n",max(ruu,chu));}int main(){    while(~scanf("%d",&n))    {        init();        for(int i=1;i<=n;i++)        {            int v;            while(1)            {                scanf("%d",&v);                if(v==0)break;                add(i,v);                add2(v,i);            }        }        Kosaraju();    }}









0 0