分析部分摘自:http://www.cnblogs.com/kuangbin/archive/2011/08/07/2130277.html
强连通分量缩点求入度为0的个数和出度为0的分量个数
题目大意:N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
也就是:
给定一个有向图,求:
1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点
顶点数<= 100
解题思路:
1. 求出所有强连通分量
2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少
在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少
加边的方法:
要为每个入度为0的点添加入边,为每个出度为0的点添加出边
假定有 n 个入度为0的点,m个出度为0的点,如何加边?
把所有入度为0的点编号 0,1,2,3,4 ....N -1
每次为一个编号为i的入度0点可达的出度0点,添加一条出边,连到编号为(i+1)%N 的那个出度0点,
这需要加n条边
若 m <= n,则
加了这n条边后,已经没有入度0点,则问题解决,一共加了n条边
若 m > n,则还有m-n个入度0点,则从这些点以外任取一点,和这些点都连上边,即可,这还需加m-n条边。
所以,max(m,n)就是第二个问题的解
此外:当只有一个强连通分支的时候,就是缩点后只有一个点,虽然入度出度为0的都有一个,但是实际上不需要增加清单的项了,所以答案是1,0;
Sample Input
5 2 4 3 0 4 5 0 0 0 1 0
Sample Output
1 2
Source
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 const int MAXN=20010;//点数 5 const int MAXM=50010;//边数 6 struct Edge 7 { 8 int to,next; 9 }edge[MAXM]; 10 int head[MAXN],tot; 11 int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~scc 12 int Index,top; 13 int scc;//强连通分量的个数 14 bool Instack[MAXN]; 15 int num[MAXN];//各个强连通分量包含点的个数,数组编号1~scc 16 //num数组不一定需要,结合实际情况 17 int out[MAXN],tmp,Num,ans,in[MAXN]; 18 void addedge(int u,int v) 19 { 20 edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++; 21 } 22 void Tarjan(int u) 23 { 24 int v; 25 Low[u]=DFN[u]=++Index; 26 Stack[top++]=u; 27 Instack[u]=true; 28 for(int i=head[u];i != -1;i=edge[i].next) 29 { 30 v=edge[i].to; 31 if(!DFN[v]) 32 { 33 Tarjan(v); 34 if(Low[u] > Low[v])Low[u]=Low[v]; 35 } 36 else if(Instack[v] && Low[u] > DFN[v]) 37 Low[u]=DFN[v]; 38 } 39 if(Low[u]==DFN[u]) 40 { 41 scc++; 42 do 43 { 44 v=Stack[--top]; 45 Instack[v]=false; 46 Belong[v]=scc; 47 num[scc]++; 48 } 49 while(v != u); 50 } 51 } 52 void solve(int N) 53 { 54 memset(out,0,sizeof(out)); 55 memset(in,0,sizeof(in)); 56 memset(Belong,0,sizeof(Belong)); 57 memset(DFN,0,sizeof(DFN)); 58 memset(Instack,false,sizeof(Instack)); 59 memset(num,0,sizeof(num)); 60 Index=scc=top=0; 61 for(int i=1;i <= N;i++) 62 if(!DFN[i]) 63 Tarjan(i); 64 } 65 void init() 66 { 67 tot=0; 68 memset(head,-1,sizeof(head)); 69 } 70 int main() 71 { 72 int n,m; 73 int i,j,v; 74 //freopen("1.in","r",stdin); 75 while(scanf("%d",&n)!=EOF) 76 { 77 init(); 78 int q,p; 79 for(i=1;i<=n;i++) 80 { 81 while(scanf("%d",&m)!=EOF) 82 { 83 if(m==0) break; 84 addedge(i,m); 85 } 86 } 87 solve(n); 88 for(i=1;i<=n;i++) 89 { 90 for(v=head[i];v!=-1;v=edge[v].next) 91 { 92 if(Belong[i]!=Belong[edge[v].to]) 93 { 94 out[Belong[i]]++; 95 in[Belong[edge[v].to]]++; 96 97 } 98 } 99 } 100 int o0=0,i0=0; 101 //printf("%d ",scc); 102 for(i=1;i<=scc;i++) 103 { 104 //printf("%d %d ",out[i],in[i]); 105 if(!out[i]) o0++; 106 if(!in[i]) i0++; 107 } 108 if(scc==1) {printf("1 0 ");continue;} 109 printf("%d ",i0); 110 printf("%d ",i0>o0?i0:o0); 111 } 112 return 0; 113 }