zoukankan      html  css  js  c++  java
  • Strongly connected HDU

    想法一:

    找出强联通块,计算每个连通块内的点数。将点数最少的那个连通块单独拿出来,其余的连通块合并成一个连通分量。 那么假设第一个连通块的 点数是 x  第二个连通块的点数是 y

    一个【强】连通图最多(每两个点之间,至少存在一条课互相到达的路径)的边数为n*(n-1)

    一个连通图的边数至少为n*(n-1)- x*y + 1

    则非连通图最多的边数为n*(n-1)- x*y 即 x*(x-1)+ y*(y-1)+ x*y

    因为原图中已经有m条边 所以最多加 x*(x-1)+ y*(y-1)+ x*y - m 条边

    这里最少点数的强联通分量要满足一个条件,就是出度或者入度为 0才行,不然是不满足的。

    二:

    缩点后

    这其实就相当于一个完全图至少减去多少条边,使之变成非强连通图

    肯定减去连通分量里点最少的那个了

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #define mem(a, b) memset(a, b, sizeof(a))
    using namespace std;
    const int maxn = 300100, INF = 0x7fffffff;
    vector<int> G[maxn];
    int pre[maxn], low[maxn], cnt[maxn], dfs_clock, scc_cnt, sccno[maxn];
    int in[maxn], out[maxn];
    stack<int> S;
    int n, m;
    
    void dfs(int u)
    {
        pre[u] = low[u] = ++dfs_clock;
        S.push(u);
        for(int i=0; i<G[u].size(); i++)
        {
            int v = G[u][i];
            if(!pre[v])
            {
                dfs(v);
                low[u] = min(low[u], low[v]);
            }
            else if(!sccno[v])
            {
                low[u] = min(low[u], pre[v]);
            }
        }
        if(low[u] == pre[u])
        {
            scc_cnt++;
            for(;;)
            {
                int x = S.top(); S.pop();
                sccno[x] = scc_cnt;     //标记x属于哪一个强连通块
                cnt[scc_cnt]++;     //统计当前强连通块中元素的个数
                if(x == u) break;
            }
        }
    }
    
    void init()
    {
    
        mem(cnt, 0);
        mem(pre, 0);
        mem(in, 0);
        mem(out, 0);
        mem(low, 0);
        mem(sccno, 0);
        for(int i=0; i<=n; i++) G[i].clear();
        dfs_clock = 0;
        scc_cnt = 0;
    }
    
    
    
    int main()
    {
        int T, kase = 0;
        cin>> T;
        while(T--)
        {
            cin>> n >> m;
            init();
            for(int i=0; i<m; i++)
            {
                int u, v;
                cin>> u >> v;
                G[u].push_back(v);
            }
            for(int i=1; i<=n; i++)
                if(!pre[i])
                    dfs(i);
            int minx = INF;
            for(int i=1; i<=n; i++)
                for(int j=0; j<G[i].size(); j++)
                    if(sccno[i] != sccno[G[i][j]])
                        out[sccno[i]]++, in[sccno[G[i][j]]]++;
            for(int i=1; i<=scc_cnt; i++)
                if(in[i] == 0 || out[i] == 0)
                    minx = min(minx, cnt[i]);
           // cout<< minx <<endl;
            printf("Case %d: ",++kase);
            if(scc_cnt == 1) cout<< "-1" <<endl;
            else cout<< n*(n-1) - minx*(n-minx) - m <<endl;
    
    
        }
    
        return 0;
    }
    自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
  • 相关阅读:
    一个泛型栈类(GenericStack)
    Google Maps API v2初探
    浅谈工作中celery与Redis遇到的一些问题 PTSD
    python PTSD
    77%的Linux运维都不懂的内核问题
    教程 | Linux常用命令大全
    分布式架构系列: 负载均衡技术详解
    10大Python开源项目推荐(Github平均star2135)
    你必须学写 Python 装饰器的五个理由
    五分钟搞定 Linux 文档全部知识,就看这篇文章
  • 原文地址:https://www.cnblogs.com/WTSRUVF/p/9304754.html
Copyright © 2011-2022 走看看