poj 1236 scc强连通分量

分析部分摘自: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 }
原文地址:https://www.cnblogs.com/cnblogs321114287/p/4280181.html