• 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 }
  • 相关阅读:
    win10使用Scoop软件包管理器,支持版本切换
    使用ddns-go实现本地IP或公网IP动态域名解析
    使用Frp实现内网穿透
    Win10开发环境搭建
    Java使用Jabba进行版本管理
    Win10将用户目录Users迁移到其他盘
    【测试开发】十五、接口测试-接口定义-实现接口编辑功能
    【测试开发】十四、接口测试-接口定义功能-前后端-实现新增
    【测试开发】十三、接口测试-接口定义功能-前端-实现动态增删表单
    【测试开发】十二、接口测试-实现接口列表功能-递归查询子节点下的接口
  • 原文地址:https://www.cnblogs.com/cnblogs321114287/p/4280181.html
Copyright © 2020-2023  润新知