poj 1236

题目大意:

    一些学校连成了网络, 在学校之间存在某个协议:每个学校都维护一张传送表,表明他们要负责将收到的软件传送到表中的所有学校。如果A在B的表中,那么B不一定在A的表中。

    现在的任务就是,给出所有学校及他们维护的表,问1、如果所有学校都要被传送到,那么需要几份软件备份;2、如果只用一份软件备份,那么需要添加几条边?

思路:首先找连通分量,然后看连通分量的入度为0点的总数,出度为0点的总数,那么问要向多少学校发放软件,就是入度为零的个数,这样才能保证所有点能够找到
然后第二问添加多少条边可以得到使整个图达到一个强连通分量,答案是入度为0的个数和出度为0的个数中最大的





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


 #include<stdio.h>
#include<string.h>
#include<math.h>
#include<stack>
#include<vector>
#include<iostream>
#define MAX 110
using namespace std;
int vis[MAX];
int belong[MAX];//记录节点属于哪一个强连通分量
int dfn[MAX],low[MAX];

vector<int>gra[MAX];
stack<int>s;
int index;
int count1;//记录强连通分量的个数及编号
int out[MAX],in[MAX];
int n,m;
void tarjan(int pos)
{
    int i;//在i若定义成全局变量就wa,为保险起见 若函数内部和main函数用到同样的变量名(如i)在函数内部和main函数分别定义

    dfn[pos]=low[pos]=++index;
    vis[pos]=1;
    s.push(pos);
    for(i=0;i<gra[pos].size();i++)
    {
        int next=gra[pos][i];
        if(!dfn[next])
        {
            tarjan(next);
            low[pos]=min(low[pos],low[next]);
        }
        else
        if(vis[next]==1)
        {
            low[pos]=min(low[pos],dfn[next]);
        }
    }


    if(dfn[pos]==low[pos])
    {
        count1++;
        while(1)
        {
            int t=s.top();
            belong[t]=count1;

            vis[t]=0;//说明已经不在栈内
            s.pop();
            
            if(t==pos)
            break;
        }

    }

}




int main()
{

    int a;
    int i,j;
    int ans2;
    while(scanf("%d",&n)!=EOF)
    {
        memset(vis,0,sizeof(vis));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(belong,0,sizeof(belong));
         for(i=0;i<MAX;i++)
        {
            gra[i].clear();
        }
        while(!s.empty())
        {
            s.pop();

        }


        for(i=1;i<=n;i++)
        {
            while(scanf("%d",&a),a)
            {
                gra[i].push_back(a);
            }
        }

        index=count1=0;//初始化不能忘
        for(i=1;i<=n;i++)
        {
            if(!dfn[i])
            {
                tarjan(i);
            }
        }
        memset(out,0,sizeof(out));
        memset(in,0,sizeof(in));
        for(i=1;i<=n;i++)
        {
            for(j=0;j<gra[i].size();j++)
            {
                if(belong[i]!=belong[gra[i][j]])//两个点不属于同一个强连通分量
                {
                    out[belong[i]]++;
                    in[belong[gra[i][j]]]++;

                }
            }
        }
        int out1=0;
        int in1=0;
        for(i=1;i<=count1;i++)
        {
            if(out[i]==0)
            {
                out1++;
            }
             if(in[i]==0)
            {
                in1++;
            }
        }




        if(count1==1)
        printf("1\n0\n");

        else{
        ans2=max(out1,in1);
        printf("%d\n",in1);
        printf("%d\n",ans2);
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值