[POJ 1236][IOI 1996]Network of Schools

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


题目大意:给定一个有向图,求至少要有多少个点, 才能从这些点出发到达所有点;至少要添加多少条边,才能从任意一点出发到达所有点

首先要推出一个定理:在DAG中,对于所有入度不为0的点,一定有入度为0的点可达(因为从入度为0的点倒着走,一定能走到入度不为0的点)

于是此题可用tarjan缩点,求有多少个入度为0的点,这就是第一个问题的答案。

第二个问题的答案为入度为0的点和出度为0的点的最小值,证明比较难,略。

对于这道题,因为只要求入度和出度为0的点,故只需在tarjan过程中记录每个点归属哪个强连通分量,然后统计输出即可

#include <iostream>
#include <stdio.h>
#include <string.h>

#define MAXE 500
#define MAXV 3000

using namespace std;

int N;

struct edge
{
    int u,v,next;
}edges[MAXV];

int head[MAXE],nCount=0;
int dfn[MAXE],low[MAXE],index=0;
int belong[MAXE],tot=0; //belong[i]=i点所属的强连通分量,tot=强连通分量总数
bool inStack[MAXE];
int stack[MAXE*4],top=0;
bool map[MAXE][MAXE];
int inDegree[MAXE],outDegree[MAXE],inZero=0,outZero=0; //入度,出度

int max(int a,int b)
{
    if(a>b) return a;
    return b;
}

int min(int a,int b)
{
    if(a<b) return a;
    return b;
}

void AddEdge(int U,int V)
{
    edges[++nCount].u=U;
    edges[nCount].v=V;
    edges[nCount].next=head[U];
    head[U]=nCount;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++index;
    stack[++top]=u; //该点入栈
    inStack[u]=true;
    for(int p=head[u];p!=-1;p=edges[p].next)
    {
        int v=edges[p].v;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(inStack[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    int v;
    if(dfn[u]==low[u])
    {
        tot++;
        do
        {
            v=stack[top--];
            belong[v]=tot;
            inStack[v]=false;
        }
        while(u!=v);
    }
}

int main()
{
    int to;
    cin>>N;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=N;i++)
    {
        while(1)
        {
            cin>>to;
            if(to==0) break;
            AddEdge(i,to);
            map[i][to]=true;
        }
    }
    for(int i=1;i<=N;i++)
        if(!dfn[i]) tarjan(i);
    for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++)
        {
            if(map[i][j]&&belong[i]!=belong[j])
            {
                inDegree[belong[j]]++;
                outDegree[belong[i]]++;
            }
        }
    for(int i=1;i<=tot;i++)
    {
        if(!inDegree[i]) inZero++;
        if(!outDegree[i]) outZero++;
    }
    if(tot==1) cout<<1<<endl<<0<<endl;
    else cout<<inZero<<endl<<max(inZero,outZero)<<endl;
    return 0;
}



你可能感兴趣的:(Tarjan,强连通分量)