POJ1236 Network of Schools —— 强连通分量 + 缩点 + 入出度
题目链接:http://poj.org/problem?id=1236
Network of Schools
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 19859 | Accepted: 7822 |
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.
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
题解:
1.利用Tarjan算法求出每个强连通分量,然后进行缩点(以下的分析中,结点是指经过缩点之后的强连通分量)。
2.如果强连通分量的个数为1,即表明题目所给的图为强连通图。故可直接输出答案:1, 0。否则:
首先求出每个强连通分量的入度和出度,然后:
task A:显然,只需要为每个入度为0的结点输入一份资料即可,其余入度不能为0的结点都可以从指向它的结点获取资料。
task B:每增加一条边,图中必有一个的结点入度增加1, 必有一个结点的出度增加1。设图中有a个结点的入度为0, b个结点的出度为0,假设a>=b,那么首先我们可以增加b条边,既能实现图中所有结点的出度都不能为0,但是还剩下a-b个结点的入度为0,此时,我们只需再添加a-b条边,既可以实现图中所有结点的入度都不为0了,所以总共需要添加a条边。当b>a时,需要添加b条边。综上结论:如果图中有a个结点的入度为0, b个结点的出度为0,那么只需添加 max(a,b)条边,即可使原图成为强连通图。前提是原图为简单图,且结点个数大于1。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <vector> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 #define ms(a,b) memset((a),(b),sizeof((a))) 13 using namespace std; 14 typedef long long LL; 15 const double EPS = 1e-8; 16 const int INF = 2e9; 17 const LL LNF = 2e18; 18 const int MAXN = 1e2+10; 19 20 struct Edge 21 { 22 int to, next; 23 }edge[MAXN*MAXN]; 24 int head[MAXN], tot; 25 26 int index, Low[MAXN], DFN[MAXN]; 27 int top, Stack[MAXN], Instack[MAXN]; 28 int scc, Belong[MAXN]; 29 int Indegree[MAXN], Outdegree[MAXN]; 30 31 void addedge(int u, int v) 32 { 33 edge[tot].to = v; 34 edge[tot].next = head[u]; 35 head[u] = tot++; 36 } 37 38 void Tarjan(int u) 39 { 40 int v; 41 Low[u] = DFN[u] = ++index; 42 Stack[top++] = u; 43 Instack[u] = 1; 44 for(int i = head[u]; i!=-1; i = edge[i].next) 45 { 46 v = edge[i].to; 47 if(!DFN[v]) 48 { 49 Tarjan(v); 50 Low[u] = min(Low[u], Low[v]); 51 } 52 else if(Instack[v]) 53 Low[u] = min(Low[u], Low[v]); 54 } 55 56 if(Low[u]==DFN[u]) 57 { 58 scc++; 59 do 60 { 61 v = Stack[--top]; 62 Instack[v] = 0; 63 Belong[v] = scc; 64 }while(v!=u); 65 } 66 } 67 68 void init() 69 { 70 tot = 0; 71 memset(head, -1, sizeof(head)); 72 73 index = scc = top = 0; 74 memset(DFN, 0, sizeof(DFN)); 75 memset(Low, 0, sizeof(Low)); 76 memset(Instack, 0, sizeof(Instack)); 77 78 memset(Indegree, 0, sizeof(Indegree)); 79 memset(Outdegree, 0, sizeof(Outdegree)); 80 } 81 82 int main() 83 { 84 int n; 85 while(scanf("%d",&n)!=EOF) 86 { 87 init(); 88 for(int u = 1; u<=n; u++) 89 { 90 int v; 91 while(scanf("%d", &v) && v) 92 addedge(u, v); 93 } 94 95 for(int i = 1; i<=n; i++) 96 if(!DFN[i]) 97 Tarjan(i); 98 99 if(scc==1) 100 { 101 printf("%d\n%d\n", 1, 0); 102 continue; 103 } 104 105 for(int u = 1; u<=n; u++) 106 { 107 for(int i = head[u]; i!=-1; i = edge[i].next) 108 { 109 int v = edge[i].to; 110 if(Belong[u]==Belong[v]) continue; 111 Outdegree[Belong[u]]++; 112 Indegree[Belong[v]]++; 113 } 114 } 115 116 int Innum = 0, Outnum = 0; 117 for(int i = 1; i<=scc; i++) 118 { 119 if(Indegree[i]==0) Innum++; 120 if(Outdegree[i]==0) Outnum++; 121 } 122 123 printf("%d\n%d\n", Innum, max(Innum, Outnum)); 124 } 125 }