POJ 1236 Network of Schools (强连通分量+缩点)

Network of Schools
Time Limit: 1000MS  Memory Limit: 10000K
Total Submissions: 8935  Accepted: 3523

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

水题。题目有两问,第一问求的是找到最少的点使得信息能覆盖整个图,第二问是加最少的边使该图成为强连通图。直接用tarjan求出各强连通分量,进行缩点,显然选择所有入度为0的点就能覆盖整个图了。几乎入度为0和出度为0的点的个数,二者中较大者就是需要添加的边数。随便画个图就一目了然了。注意只有一个强连通分量时,说明图本来就是强连通的,这时应该输出1和0。这里如果不特判一下,将输出1和1得到WA。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#define SIZE 128

using namespace std;

struct node
{
    int to,next;
}edge[SIZE*SIZE];

int head[SIZE],idx;
int dfsn[SIZE],low[SIZE],time;
bool vis[SIZE];
int belong[SIZE],num,in[SIZE],out[SIZE];
stack <int> sta;
int N;

void addnode(int from,int to)
{
    edge[idx].to = to;
    edge[idx].next = head[from];
    head[from] = idx++;
}

void tarjan(int rt)
{
    dfsn[rt] = low[rt] = ++time;
    sta.push(rt);
    vis[rt] = true;
    for(int i=head[rt]; i!=-1; i=edge[i].next)
    {
        int to = edge[i].to;
        if(!dfsn[to])
        {
            tarjan(to);
            if(low[to] < low[rt])
                low[rt] = low[to];
        }
        else if(vis[to] && dfsn[to] < low[rt])
            low[rt] = dfsn[to];
    }
    int t = 0;
    if(dfsn[rt] == low[rt])
    {
        num ++;
        while(t != rt)
        {
            t = sta.top();
            sta.pop();
            vis[t] = false;
            belong[t] = num;
        }
    }
}

void solve()
{
    memset(dfsn,0,sizeof(dfsn));
    memset(vis,0,sizeof(vis));
    memset(belong,0,sizeof(belong));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    time = num = 0;
    for(int i=1; i<=N; i++)
        if(!dfsn[i])
            tarjan(i);
    if(num == 1)
    {
        puts("1");
        puts("0");
        return;
    }
    for(int i=1; i<=N; i++)
    {
        for(int j=head[i]; j!=-1; j=edge[j].next)
        {
            int to = edge[j].to;
            if(belong[i] != belong[to])
            {
                out[belong[i]] ++;
                in[belong[to]] ++;
            }
        }
    }
    int IN = 0, OUT = 0;
    for(int i=1; i<=num; i++)
    {
        if(!in[i]) IN++;
        if(!out[i])OUT++;
    }
    printf("%d\n",IN);
    printf("%d\n",max(IN,OUT));
}

int main()
{
    while(~scanf("%d",&N))
    {
        int tem;
        idx = 0;
        memset(head,-1,sizeof(head));
        for(int i=1; i<=N; i++)
        {
            while(scanf("%d",&tem) && tem)
                addnode(i,tem);
        }
        solve();
    }
    return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值