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;
    }
    自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
  • 相关阅读:
    彻底屏蔽淘宝网、易趣
    日期处理string 与 DateTime相互转化
    手机进水!!!!!!!!!
    解决VS.net "Automation 服务器不能创建对象"
    综艺大哥大
    计算当前日期是任意时间段内第几周的函数
    吉祥三宝>馒头无极版
    如何在ASP.NET中使用JavaScript脚本
    IDEA工具开发一些辅助功能设置
    Linux命令行模式下挂载U盘与光驱
  • 原文地址:https://www.cnblogs.com/WTSRUVF/p/9304754.html
Copyright © 2011-2022 走看看