zoukankan      html  css  js  c++  java
  • HDU 4635

    http://acm.hdu.edu.cn/showproblem.php?pid=4635

    问:最多加多少条边,使得原图不是强连通图

    正向考虑有困难,不妨反向思考,既最少去掉几条边使得原图不是强连通。

    总边数sum=n*(n-1)时肯定是强连通,已经给了m条边,sum-=m

    这时把已经强连通的部分进行缩点,对于缩好的点我们把他们分成两部分,保证其中一部分到另一部分没有边(这两部分不强连通),再把sum减去两部分能构成所有的边数,取最大值即为答案

    具体做时枚举每个小强连通块,找到num[i]*(n-num[i])最小的情况(num[i]为小强连通块点数),其中必须出度或入度为0的连通块才可以被选择

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    #include <map>
    using namespace std ;
    const int INF=0xfffffff ;
    struct node 
    {
        int s,t,nxt ;
    }e[4000005] ;
    int n,m,idx,ans,tp,cnt,num[100005],IN[100005],OUT[100005],dfn[100005],vis[100005],low[100005],head[100005],st[100005],belong[100005] ;
    void add(int s,int t)
    {
        e[cnt].s=s ;
        e[cnt].t=t ;
        e[cnt].nxt=head[s] ;
        head[s]=cnt++ ;
    }
    void tarjan(int u)
    {
        dfn[u]=low[u]=++idx ;
        vis[u]=1 ;
        st[++tp]=u ;
        int v ;
        for(int i=head[u] ;i!=-1 ;i=e[i].nxt)
        {
            v=e[i].t ;
            if(!dfn[v])
            {
                tarjan(v) ;
                low[u]=min(low[u],low[v]) ;
            }
            else if(vis[v])
                low[u]=min(low[u],dfn[v]) ;
        }
        if(dfn[u]==low[u])
        {
            ans++ ;
            while(1)
            {
                v=st[tp--] ;
                vis[v]=0 ;
                belong[v]=ans ;
                num[ans]++ ;
                if(v==u)break ;
            }
        }
    }
    void sc()
    {
        memset(vis,0,sizeof(vis)) ;
        memset(dfn,0,sizeof(dfn)) ;
        memset(num,0,sizeof(num)) ;
        idx=tp=ans=0 ;
        for(int i=1 ;i<=n ;i++)
            if(!dfn[i])
                tarjan(i) ;
    }
    int main()
    {
        int T ;
        scanf("%d",&T) ;
        for(int cas=1 ;cas<=T ;cas++)
        {
            cnt=0 ;
            memset(head,-1,sizeof(head)) ;
            scanf("%d%d",&n,&m) ;
            for(int i=0 ;i<m ;i++)
            {
                int s,t ;
                scanf("%d%d",&s,&t) ;
                add(s,t) ;
            }
            sc() ;
            if(ans==1)
            {
                printf("Case %d: -1
    ",cas) ;
                continue ;
            }
            memset(IN,0,sizeof(IN)) ;
            memset(OUT,0,sizeof(OUT)) ;
            for(int u=1 ;u<=n ;u++)
            {
                for(int i=head[u] ;i!=-1 ;i=e[i].nxt)
                {
                    int tt=e[i].t ;
                    if(belong[tt]==belong[u])continue ;
                    IN[belong[tt]]++ ;
                    OUT[belong[u]]++ ;
                }
            }
            int ret=-1 ;
            for(int i=1 ;i<=ans ;i++)
            {
                if(!IN[i] || !OUT[i])
                    ret=max(ret,n*(n-1)-m-num[i]*(n-num[i])) ;
            }
            printf("Case %d: %d
    ",cas,ret) ;
        }
        return 0 ;
    }
    View Code
  • 相关阅读:
    创建react项目
    解决移动端弹窗下页面滚动问题
    前端常用的几种加密方式
    http请求状态码
    vue代理配置
    自动化测试实操案例详解 | Windows应用篇
    Google 再见 Java
    一次诡异的 SQL 数量统计查询不准的问题
    Maven
    淘宝技术分享:手淘亿级移动端接入层网关的技术演进之路
  • 原文地址:https://www.cnblogs.com/xiaohongmao/p/3726773.html
Copyright © 2011-2022 走看看