zoukankan      html  css  js  c++  java
  • HDU4635 Strongly connected【强连通】

    题意:

    给一个n个点的简单有向图,问最多能加多少条边使得该图仍然是简单有向图,且不是强连通图。简单有向图的定义为:没有重边,无自环。 强连通图的定义为:整个图缩点后就只有一个点,里面包含n个原点,也就是一个连通分量。如果一开始就是一个强连通图,则输出-1。

    思路:

    要加边最多那么加边后的图连通分量越少越好,那么连通分量最少也就是2个。先用n个点构造一个完全图(有向图有:n*(n-1)条边,无向图有:n*(n-1)/2条边),再用构造的边 减去原来有的m条边=ans。再用强连通算法缩点,记录每个新点包含点的个数,从入度为0或出度为0的新点中找出包含点数最小的minnum,再用上面剩余的边ans - minnum*(n-minnum)就是所要的答案。因为如果不减入度为0或出度为0相关的边,那么该点本身包含有入边和出边,加的边永远都是强连通图。所以只能去掉与入度为0或出度为0点的相关边,只减掉一个方向的边,要么全是(n-minnum)点数到minnum点数的入边,那么是minnum点数到(n-minnum)点数的出边。

    代码:

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    const int N = 100005;
    struct EDG{
        int to,next;
    }edg[N];
    
    int eid,head[N],low[N],dfn[N],vist[N],num[N],id[N],deep,stack1[N],tn,top,in[N],out[N];
    
    void init()
    {
        eid=tn=top=deep=0;
        memset(head,-1,sizeof(head));
        memset(vist,0,sizeof(vist));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(num,0,sizeof(num));
    }
    
    void addEdg(int u,int v)
    {
        edg[eid].to=v; edg[eid].next=head[u]; head[u]=eid++;
    }
    
    void Tarjan(int u)
    {
        stack1[++top]=u;
        vist[u]=1;
        deep++;
        low[u]=dfn[u]=deep;
        for(int i=head[u]; i!=-1; i=edg[i].next)
        {
            int v=edg[i].to;
            if(vist[v]==0)
            {
                vist[v]=1;
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(vist[v]==1)
                low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u])
        {
            tn++;
            do{
                vist[stack1[top]]=2;
                num[tn]++;
                id[stack1[top]]=tn;
            }while(stack1[top--]!=u);
    
        }
    }
    
    long long solve(int n,int m)
    {
        long long ans=n*(n-1)-m;
        int minnum=N;
        for(int i=1; i<=n; i++)
            if(vist[i]==0)
             Tarjan(i);
        if(tn==1) return -1;
        for(int u=1; u<=n; u++)
        for(int i=head[u]; i!=-1; i=edg[i].next)
        {
            int v=edg[i].to;
            if(id[u]!=id[v])
                in[id[v]]++,out[id[u]]++;
        }
        for(int i=1; i<=tn; i++)
        if(in[i]==0||out[i]==0)
        {
            minnum=min(minnum,num[i]);
        }
        ans-=minnum*(n-minnum);
        return ans;
    }
    
    int main()
    {
        int t,n,m,c=0,a,b;
        cin>>t;
        while(t--)
        {
            cin>>n>>m;
            init();
            for(int i=1; i<=m; i++)
            {
                cin>>a>>b;
                addEdg(a,b);
            }
            printf("Case %d: %I64d
    ",++c,solve(n,m));
        }
    }
    View Code
  • 相关阅读:
    linux 命令——48 watch (转)
    linux 命令——47 iostat (转)
    linux 命令——46 vmstat(转)
    linux 命令——45 free(转)
    linux 命令——44 top (转)
    linux 命令——43 killall(转)
    linux 命令——42 kill (转)
    linux 命令——41 ps(转)
    linux 命令——40 wc (转)
    Java for LeetCode 068 Text Justification
  • 原文地址:https://www.cnblogs.com/darklights/p/7661632.html
Copyright © 2011-2022 走看看