POJ1236强连通+缩点

Network of Schools
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 9642   Accepted: 3832

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


/*******************************************************************
* 题意:一些学校连成了网络, 在学校之间存在某个协议:每个学校都维护
* 一张传送表,表明他们要负责将收到的软件传送到表中的所有学校。如果A在B的表中,
* 那么B不一定在A的表中。
* 现在的任务就是,给出所有学校及他们维护的表,问1、如果所有学校都要被传送到,
* 那么需要几份软件备份;2、如果只用一份软件备份,那么需要添加几条边?
*
* 思路: 这道题就是求学校之间连成网络的强联通分量。第一问中软件只要在一个分量中存在一份,那么分量中的其他学校必然也可以拿到这份软件;第二问中要所有学校都连成一个强联通分量,
* 只需要将图中的强联通分量互相之间联通就好了。
* 添加的边数就是缩点后入度为0的点和出度为0的点的最大值。
*
* Problem:POJ1236Network of Schools----强连通缩点
* author: sgx
* date: 2013/09/07
* 版本: 邻接矩阵,关键用邻接表判断两点间是否有边有点麻烦;
*********************************************************************/
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>

#define A system("pause")

using namespace std;

const int maxn=100+5;

int map[maxn][maxn];

int dfn[maxn],low[maxn],stack[maxn];
bool instack[maxn];

int indegree[maxn],outdegree[maxn];
int belong[maxn];

int top,Bcnt,index;

int m,n;

inline int min(int a,int b)
{
    return a<b?a:b;
}

inline int max(int a,int b)
{
    return a>b?a:b;
}

void tarjan(int u)
{
     int v;
     dfn[u]=low[u]=++index;
     stack[++top]=u;
     instack[u]=true;

     for(int i=1;i<=n;i++)//枚举每条边;
     {
        if(map[u][i])//找到邻接点;
        {
            if(!dfn[i])//若未访问过则访问该点;
            {
                 tarjan(i);
                 low[u]=min(low[u],low[i]);//树边;
            }
            else if(instack[i])
             {
                 low[u]=min(low[u],dfn[i]);//后向边;
            }
         }
     }
    if(dfn[u]==low[u])
     {
         Bcnt++;
         do
         {
             v=stack[top--];//弹出栈顶元素;
            belong[v]=Bcnt;//标记强连通分量;
            instack[v]=false;
         }while(v!=u);
     }
}

void solve()
{
    int i;

     top=index=Bcnt=0;
     memset(instack,0,sizeof(instack));
     memset(dfn,0,sizeof(dfn));
     memset(low,0,sizeof(low));
     memset(indegree,0,sizeof(indegree));
     memset(outdegree,0,sizeof(outdegree));

     for(i=1;i<=n;i++)
     {
        if(!dfn[i])//如果某点没被访问过,则对其进行tarjan;
             tarjan(i);//tarjan结果是得到了belong数组,记录每个节点分别属于哪个强联通分量
     }

     for(int i=1;i<=n;i++)
     {
         for(int j=1;j<=n;j++)
         {
            if(map[i][j]&&belong[i]!=belong[j])//两点之间有边,但不是属于一个强联通分量的边
            {
                 outdegree[belong[i]]++; // 缩点后的点入度+1
                 indegree[belong[j]]++;// 缩点后的点出度+1

             }
         }
     }
     int cnt1=0,cnt2=0;

     for(int i=1;i<=Bcnt;i++)
     {
        if(!indegree[i])
             cnt1++;
        if(!outdegree[i])
             cnt2++;
     }
     if(Bcnt==1)
         printf("1\n0\n");
     else
         printf("%d\n%d\n",cnt1,max(cnt1,cnt2));
}

int main()
{
     while(scanf("%d",&n)!=EOF)
     {
         memset(map,0,sizeof(map));

         for(int u=1;u<=n;u++)
         {
            int v;
            while(scanf("%d",&v)&&v)
                 map[u][v]=1;
         }

         solve();
   }
   return 0;
}
/*PS:这个题目第一次接触,A的好艰难,结果最后发现两处错误,Bcnt的初始值设错了
*还有就是少打了个=。。细心啊!!YM下byvoid大牛,讲的很棒~~*/
 


 



   

        
     
               

 

你可能感兴趣的:(POJ1236强连通+缩点)