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\n",scc);

102         for(i=1;i<=scc;i++)

103         {

104             //printf("%d %d\n",out[i],in[i]);

105             if(!out[i]) o0++;

106             if(!in[i])  i0++;

107         }

108         if(scc==1) {printf("1\n0\n");continue;}

109         printf("%d\n",i0);

110         printf("%d\n",i0>o0?i0:o0);

111     }

112     return 0;

113 }

 

你可能感兴趣的:(poj)