zoukankan      html  css  js  c++  java
  • HDU 4635 Strongly connected (强连通分量+缩点)

    <题目链接>

    题目大意:

    给你一张有向图,问在保证该图不能成为强连通图的条件下,最多能够添加几条有向边。

    解题分析:

    我们从反面思考,在该图是一张有向完全图的情况下,最少删去几条边能够使其不是强连通图。即,开始的时候,图的总边树为 n*(n-1),减去m条已有的边。然后把原图中所有的强连通块进行缩点,对于缩好的点,我们把其分成两部分,保证这两部分点不能够相互可达(即这两部分不是强连通),所以我们要减去一个部分到另一部分的所有同一方向的边,比如将连通块1到连通块2的所有边都删除,这样,这两部分点就不强连通,整张图也不是强连通图。那如何使删除的边最小呢?因为删除的边为cnt*(n-cnt),根据简单的数学常识,必然是cnt和(n-cnt)差值最大的时候,他们的乘积最小,所以我们只要记录所有连通块中点数最少的数量即可。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 
     7 typedef long long ll;
     8 const int N = 200010;
     9 const int INF = 0x3f3f3f3f;
    10 
    11 struct Edge{
    12     int to,next;
    13 }edge[N<<1];
    14 
    15 ll n,m,cnt,head[N];
    16 ll tot,top,atype;
    17 ll dfn[N],low[N],vis[N],stack[N],belong[N],indeg[N],outdeg[N],sum[N];
    18 void init(){
    19     cnt=0,tot=0,top=0,atype=0;;
    20     memset(head,-1,sizeof(head));
    21     memset(dfn,0,sizeof(dfn));
    22     memset(low,0,sizeof(low));
    23     memset(vis,0,sizeof(vis));
    24     memset(belong,0,sizeof(belong));
    25     memset(indeg,0,sizeof(indeg));
    26     memset(outdeg,0,sizeof(outdeg));
    27     memset(sum,0,sizeof(sum));
    28 }
    29 void addedge(int u,int v){
    30     edge[++cnt].to=v,edge[cnt].next=head[u];
    31     head[u]=cnt;
    32 }
    33 void Tarjan(int u){
    34     dfn[u]=low[u]=++tot;
    35     stack[top++]=u;
    36     vis[u]=1;
    37     for(int i=head[u];i!=-1;i=edge[i].next){
    38         int v=edge[i].to;
    39         if(!dfn[v]){
    40             Tarjan(v);
    41             low[u]=min(low[u],low[v]);
    42         }else if(vis[v]){
    43             low[u]=min(low[u],dfn[v]);
    44         }
    45     }
    46     if(dfn[u]==low[u]){
    47         atype++;
    48         int v;
    49         do{
    50             v=stack[--top];
    51             belong[v]=atype;  //将该强连通块缩点染色
    52             sum[atype]++;    //统计该强连通块的点的数量  
    53             vis[v]=0;
    54         }while(u!=v);
    55     }
    56 }
    57 
    58 int main(){
    59     int t,cases=0;
    60     scanf("%d",&t);
    61     while(t--){
    62         scanf("%lld%lld",&n,&m);
    63         init();
    64         for(int i=0;i<m;i++){
    65             int u,v;scanf("%d%d",&u,&v);
    66             addedge(u,v);
    67         }
    68         for(int i=1;i<=n;i++)
    69             if(!dfn[i])Tarjan(i);
    70         if(atype==1){
    71             printf("Case %d: -1
    ",++cases);
    72             continue;
    73         }
    74         for(int u=1;u<=n;u++)
    75             for(int i=head[u];i!=-1;i=edge[i].next){
    76                 int v=edge[i].to;
    77                 if(belong[u]!=belong[v]){    //统计每个连通块的初度和入度
    78                     outdeg[belong[u]]++;
    79                     indeg[belong[v]]++;
    80                 }
    81             }
    82         ll ans=0,cnt=INF;
    83         for(int i=1;i<=atype;i++)
    84             if(indeg[i]==0||outdeg[i]==0)   //更新初度和入读为0的联通块的数量最小值,因为只需删除一个方向的边
    85                 cnt=min(cnt,sum[i]);
    86         ans=n*(n-1)-m-cnt*(n-cnt);     //n*(n-1)为有向完全图的所有边,m为原图已有的边,cnt*(n-cnt)为分成两部分后删除一个方向的边
    87         printf("Case %d: %lld
    ",++cases,ans);
    88     }
    89     return 0;
    90 }

    2018-11-08

  • 相关阅读:
    JAVA基础——编程练习(二)
    JAVA基础——面向对象三大特性:封装、继承、多态
    JVM内存
    50. Pow(x, n) (JAVA)
    47. Permutations II (JAVA)
    46. Permutations (JAVA)
    45. Jump Game II (JAVA)
    43. Multiply Strings (JAVA)
    42. Trapping Rain Water (JAVA)
    41. First Missing Positive (JAVA)
  • 原文地址:https://www.cnblogs.com/00isok/p/9931942.html
Copyright © 2011-2022 走看看