zoukankan      html  css  js  c++  java
  • HDU4625:Strongly connected(思维+强连通分量)

    Strongly connected

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 4765    Accepted Submission(s): 1880

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635

    Description:

    Give a simple directed graph with N nodes and M edges. Please tell me the maximum number of the edges you can add that the graph is still a simple directed graph. Also, after you add these edges, this graph must NOT be strongly connected.
    A simple directed graph is a directed graph having no multiple edges or graph loops.
    A strongly connected digraph is a directed graph in which it is possible to reach any node starting from any other node by traversing edges in the direction(s) in which they point. 

    Input:

    The first line of date is an integer T, which is the number of the text cases.
    Then T cases follow, each case starts of two numbers N and M, 1<=N<=100000, 1<=M<=100000, representing the number of nodes and the number of edges, then M lines follow. Each line contains two integers x and y, means that there is a edge from x to y.

    Output:

    For each case, you should output the maximum number of the edges you can add.
    If the original graph is strongly connected, just output -1.

    Sample Input:

    3
    3 3
    1 2
    2 3
    3 1
    3 3
    1 2
    2 3
    1 3
    6 6
    1 2
    2 3
    3 1
    4 5
    5 6
    6 4

    Sample Output:

    Case 1: -1
    Case 2: 1
    Case 3: 15

    题意:

    给出一个有向图,保证图中无重边。现在要求加尽量多的边,使得最终的图不是强连通的,即任意两点可以互相到达,并且图中无重边。

    题解:

    可以想到,最终的图是一个二部图,设左边这部分为X,右边这部分为Y,那么X,Y之间只有单向边,同时X,Y中所有点都是强连通的,此时满足条件。

    现在的问题就是这么确定这个X,Y。假设X中有x个点,同理,Y中有y个点,然后来计算一波:

    此时图中的边数为x*(x-1)+y*(y-1)+x*y=x2+y2+x*y-x-y=(x+y)2-x*y-x-y=n2-n-x*y。现在要使得边数最大,那么x*y就尽量小,又因为x+y为定值,那么要么x尽可能小,要么y尽可能小就是了。

    然后由于图中可能存在环,我们就先用Tarjan缩点,然后选取包含点数最少,并且出度或者入度为0的那个点作为X部,之后计算一波就行了。

    代码如下:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    const int N = 1e5+5;
    int t,n,m,tot;
    int head[N],num[N],in[N],out[N];
    stack <int> s;
    struct Edge{
        int u,v,next;
    }e[N<<1],g[N<<1];
    void adde(int u,int v){
        e[tot].u=u;e[tot].v=v;e[tot].next=head[u];head[u]=tot++;
    }
    int T,cc;
    int scc[N],dfn[N],low[N],vis[N];
    void Tarjan(int u){
        dfn[u]=low[u]=++T;vis[u]=1;
        s.push(u);
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].v;
            if(!vis[v]){
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }else if(!scc[v]){
                low[u]=min(low[u],dfn[v]);
            }
        }
        if(low[u]==dfn[u]){
            cc++;int now;
            do{
                now = s.top();s.pop();
                scc[now]=cc;
                num[cc]++;
            }while(!s.empty() && now!=u);
        }
    }
    int main(){
        cin>>t;
        int Case=0;
        while(t--){
            Case++;
            memset(head,-1,sizeof(head));tot=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=m;i++){
                int u,v;
                scanf("%d%d",&u,&v);
                g[i].u=u;g[i].v=v;
                adde(u,v);
            }
            memset(dfn,0,sizeof(dfn));
            memset(scc,0,sizeof(scc));T=0;
            memset(vis,0,sizeof(vis));cc=0;
            memset(num,0,sizeof(num));
            memset(in,0,sizeof(in));
            memset(out,0,sizeof(out));
            for(int i=1;i<=n;i++){
                if(!vis[i]) Tarjan(i);
            }
            printf("Case %d: ",Case);
            if(cc==1){
                puts("-1");
                continue ;
            }
            for(int i=1;i<=m;i++){
                int u=g[i].u,v=g[i].v;
                if(scc[u]==scc[v]) continue ;
                in[scc[v]]++;out[scc[u]]++;
            }
            ll tmp = n*(n-1)-m;
            ll ans = 0;
            for(int i=1;i<=cc;i++){
                if(!in[i] || !out[i]) ans=max(ans,tmp-num[i]*(n-num[i]));
            }
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    AB测试原理及样本量计算的Python实现
    数据分析-A/B test
    数据分析-分类分析
    数据分析-漏斗模型(AARRR模型)
    置信区间的I型错误和II型错误
    tableau 计算字段
    tableau数据分层、数据组、数据集
    tableau 地图
    tableau 进阶
    tableau 基础
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/10409484.html
Copyright © 2011-2022 走看看