强连通分量 ZQUOJ 10203&&POJ 1236 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 of the input file 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 output file. 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

题目大意:N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
分析:该图的文件传输具有传递性,有强连通的特点。对于图中的一个强连通分量,只要向其中的一个点投入文件,则整个分量中的点都能得到,所以可以将一个分量缩点,缩点后得到有向无环图。
(1)对于有向无环图,入度为0的点就是要投放文件的目标,故第一个问题,就只需要计算出缩点后入度为0 的分量的个数即可。
(2)第二个问题,是在问最少加入几条边能使得原图变为强连通。缩点后形成的有向无环图,可以仿照树的定义令入度为0的点为根,出度为0 的点位叶子。强连通的一个最重要的特征就是每个点的出度和入度都不为0,显然树根和叶子都不满足条件;要是加边后的图变为强连通,其实就是在根和叶子之间连上足够的边是原图变成强连通。问题变成最少在根和叶子之间加多少边,令f为根数,g为叶子数,则答案就是max(f,g)。
注意:当缩点之后只有一个点时,答案为0。

AC代码:
View Code
 1 #include<stdio.h>
 2 #include<string.h>
 3 typedef struct
 4 {
 5     int v,next;
 6 }Node;
 7 Node e[5000];
 8 int n,count,index,top,sum1,sum2,cou;
 9 int first[101],dfn[101],low[101],stack[101],instack[101];
10 int in[101],out[101],belong[101];
11 void Tarjan(int i)     //求强连通分量
12 {
13     int j,k;
14     dfn[i]=low[i]=index++;
15     stack[++top]=i;
16     instack[i]=1;
17     for(j=first[i];j!=-1;j=e[j].next)
18     {
19         k=e[j].v;
20         if(!dfn[k])
21         {
22             Tarjan(k);
23             if(low[k]<low[i])
24                 low[i]=low[k];
25         }
26         else if(instack[k]&&dfn[k]<low[i])
27             low[i]=dfn[k];
28     }
29     if(low[i]==dfn[i])
30     {
31         count++;
32         do{
33             k=stack[top--];
34             instack[k]=0;
35             belong[k]=count;   //缩点
36         }while(k!=i);
37     }
38 }
39 int main()
40 {
41     int i,g,j,v;
42     while(scanf("%d",&n)!=EOF)
43     {
44         g=count=0; 
45         sum1=sum2=0; index=1; top=-1;
46         memset(dfn,0,sizeof(dfn));
47         memset(low,0,sizeof(low));
48         memset(instack,0,sizeof(instack));
49         memset(in,0,sizeof(in));
50         memset(out,0,sizeof(out));
51         memset(first,-1,sizeof(first));
52         for(i=1;i<=n;i++)     //建图
53             while(scanf("%d",&v)&&v)  
54             {
55                 e[g].v=v;
56                 e[g].next=first[i];
57                 first[i]=g++;
58             }
59         for(i=1;i<=n;i++)
60             if(!dfn[i])
61                 Tarjan(i);
62         for(i=1;i<=n;i++)
63             for(j=first[i];j!=-1;j=e[j].next)
64             {
65                 v=e[j].v;
66                 if(belong[i]!=belong[v])
67                 {
68                     in[belong[v]]++;   //入度
69                     out[belong[i]]++;  //出度
70                 }
71             }
72         for(i=1;i<=count;i++)
73         {
74             if(!in[i])  //统计缩点后入度为0的点的数目
75                 sum1++;
76             if(!out[i])  //统计缩点后出度为0的点的数目
77                 sum2++;
78         }
79         cou=sum1>sum2?sum1:sum2;   //max(f,g)
80         if(count==1)    //缩点后只有一个点时
81             cou=0;
82         printf("%d\n",sum1);
83         printf("%d\n",cou);
84     }
85     return 0;
86 }



原文地址:https://www.cnblogs.com/frog112111/p/2633092.html