• Strongly connected HDU


      1 //题意:
      2 //给你一个有向图,如果这个图是一个强连通图那就直接输出-1
      3 //否则,你就要找出来你最多能添加多少条边,在保证添加边之后的图依然不是一个强连通图的前提下
      4 //然后输出你最多能添加的边的数目
      5 //
      6 //题解:
      7 //1、判断是否是强连通图你可以看一下有几个点的low[x]==dfn[x],如果只有一个,那这个图就是一个强连通图
      8 //2、
      9 //假如我们有两个子图,我们可以让这两个子图中每一个图内都连上有向边(把子图内部连成完全图)。然后再在这两个子图之间连上一条有向边
     10 //这样的话它仍然不是一个强连通图,因为这两个图之间的边只能进不能出(即,图与图之间是用单向边连接的)
     11 //这个子图是什么?
     12 //这个子图就是缩点之后的点的数目,因为缩点之后肯定可以保证里面没有环。但是这个点可能是由许多点缩成的,这个点
     13 //内部就是一个子图,除了这个点之外所有点是另一个子图。
     14 //之后我们可以先让原图进行缩点,这样图中就没有了环,然后我们再找出来哪个点的出度等于1或者入读等于1
     15 //因为只有这样的点才是决定是否这个图能变成强连通图的关键
     16 //为什么要找出入或者入度为0的点,因为作为一个强连通图是没有任何一个点出度或入度为0(反证法)
     17 #include<stdio.h>
     18 #include<string.h>
     19 #include<iostream>
     20 #include<algorithm>
     21 #include<map>
     22 #include<math.h>
     23 #include<set>
     24 #include<vector>
     25 #include<queue>
     26 using namespace std;
     27 typedef long long ll;
     28 const int maxn=100005;
     29 const int mod=26;
     30 const int INF=0x3f3f3f3f;
     31 const int block=300;
     32 struct edge
     33 {
     34     ll u,v,next;
     35 } e[100005];
     36 ll dfn[maxn],low[maxn],stacks[maxn],belong[maxn],in[maxn],out[maxn],g[maxn];
     37 ll head[maxn],visit[maxn],cnt,tot,index,scc;
     38 void init()
     39 {
     40     memset(in,0,sizeof(in));
     41     memset(out,0,sizeof(out));
     42     memset(g,0,sizeof(g));
     43     memset(head,-1,sizeof(head));
     44     memset(low,0,sizeof(low));
     45     memset(dfn,0,sizeof(dfn));
     46     memset(visit,0,sizeof(visit));
     47     memset(belong,0,sizeof(belong));
     48     cnt=tot=index=scc=0;
     49 }
     50 void add_edge(ll x,ll y)
     51 {
     52     e[cnt].u=x;
     53     e[cnt].v=y;
     54     e[cnt].next=head[x];
     55     head[x]=cnt++;
     56 }
     57 ll tarjan(ll x)
     58 {
     59     dfn[x]=low[x]=++tot;
     60     stacks[++index]=x;
     61     visit[x]=1;
     62     for(ll i=head[x]; i!=-1; i=e[i].next)
     63     {
     64         if(!dfn[e[i].v])
     65         {
     66             tarjan(e[i].v);
     67             low[x]=min(low[x],low[e[i].v]);
     68         }
     69         else if(visit[e[i].v])
     70         {
     71             low[x]=min(low[x],dfn[e[i].v]);
     72         }
     73     }
     74     if(dfn[x]==low[x])
     75     {
     76         scc++;
     77         do
     78         {
     79             g[scc]++;
     80             visit[stacks[index]]=0;
     81             belong[stacks[index]]=scc;
     82             index--;
     83         }
     84         while(x!=stacks[index+1]);
     85     }
     86 }
     87 int main()
     88 {
     89     ll n,m,t,p=0;
     90     scanf("%lld",&t);
     91     while(t--)
     92     {
     93         init();
     94         scanf("%lld%lld",&n,&m);
     95         cnt=0;
     96         for(ll i=1; i<=n; ++i)
     97         {
     98             head[i]=-1;
     99             visit[i]=0;
    100             dfn[i]=0;
    101             low[i]=0;
    102         }
    103         ll mm=m;
    104         while(mm--)
    105         {
    106             ll x,y;
    107             scanf("%lld%lld",&x,&y);
    108             add_edge(x,y);
    109         }
    110         ll flag=0;
    111         for(ll i=1;i<=n;++i)
    112         {
    113             if(!dfn[i])
    114                 tarjan(i);
    115         }
    116         if(scc==1)
    117         {
    118             printf("Case %lld: -1
    ",++p);
    119         }
    120         else
    121         {
    122             for(ll i=0; i<cnt; ++i)
    123             {
    124                 ll fx=belong[e[i].u];
    125                 ll fy=belong[e[i].v];
    126                 if(fx!=fy)
    127                 {
    128                     out[fx]++;
    129                     in[fy]++;
    130                 }
    131             }
    132             ll ans=0,sum=0;
    133             for(ll i=1; i<=scc; ++i)
    134             {
    135                 if(in[i]==0 || out[i]==0)
    136                 {
    137                     sum=0;
    138                     //printf("%lld**
    ",g[i]);
    139                     ll temp=n-g[i];
    140                     //printf("%lld*
    ",temp);
    141                     sum+=temp*(temp-1);
    142                     //printf("%lld**
    ",sum);
    143                     sum+=g[i]*(g[i]-1);
    144                     //printf("%lld***
    ",sum);
    145                     sum+=g[i]*temp;
    146                     //printf("%lld****
    ",sum);
    147                     sum-=m;
    148                     ans=max(ans,sum);
    149                 }
    150 
    151             }
    152             printf("Case %lld: %lld
    ",++p,ans);
    153         }
    154     }
    155     return 0;
    156 }

     连通图和完全图的区别:
    n个顶点的完全图有n(n-1)/2条边;而连通图则不一定,但至少有n-1条边。举个例子,
    四个顶点的完全图有6条边,也就是四条边加上2条对角线;而连通图可以只包含周围四条边就可以了。

  • 相关阅读:
    Python random模块下的常用函数小结
    MySQL 数据库连接
    LeetCode 376. 摆动序列 做题小结
    LeetCode 1005. K 次取反后最大化的数组和 做题小结
    LeetCode 455. 分发饼干 做题小结
    完美解决Python与anaconda之间的冲突问题
    LeetCode 122. 买卖股票的最佳时机 II 做题小结
    LeetCode 714. 买卖股票的最佳时机含手续费 做题小结
    如何去除有道云笔记广告(windows)
    baby web
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/11673431.html
Copyright © 2020-2023  润新知