HDU 4635 Strongly connected

题目大意:

给你N个顶点,M条边的有向图,问最多加入多少条边之后,这个图仍旧是一个简单图(简单图:无重边,无自环),
并且不是强联通的。如果原始的图就是强联通的话就输出 -1.
 
1.找出强联通块,计算每个连通块内的点数。将点数最少的那个连通块单独拿出来,其余的连通块合并成一个连通分量。 那么假设第一个连通块的 点数是 x  第二个连通块的点数是 y, 已经有的边数是 m 则
ans =  x*(x-1) + y*(y-1) + x*y - m;(强联通块内边数最多是 n*(n-1) ),  
 
这里最少点数的强联通分量要满足一个条件,就是出度或者入度为 0才行,不然是不满足的。
 

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
usingnamespace std;
#define INF 0x7ffffff
#define maxn 100005
typedef longlong LL;
#define Min(a,b) (a<b?a:b)
int low[maxn], dfn[maxn], Time, m, n,  belong[maxn];
int Stack[maxn], top, blocks, sum[maxn], InDegree[maxn], OutDegree[maxn];
bool InStack[maxn];
vector<vector<int> > G;
void init()
{
    memset(InDegree, 0, sizeof(InDegree));
    memset(OutDegree, 0, sizeof(OutDegree));
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    memset(InStack, false, sizeof(InStack));
    memset(belong, 0, sizeof(belong));
    memset(sum, 0, sizeof(sum));
    blocks = Time = top = 0;
    G.clear();
    G.resize(n+2);
}
void Tarjan(int u)
{
    low[u] = dfn[u] = ++Time;
    Stack[top++] = u;
    InStack[u] = true;
    int len = G[u].size(), v;

    for(int i=0; i<len; i++)
    {
        v = G[u][i];

        if( !low[v] )
        {
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        elseif( InStack[v] )
            low[u] = min(low[u], dfn[v]);
    }

    if(low[u] == dfn[u])
    {
        do
        {
            v = Stack[--top];
            belong[v] = blocks;
            InStack[v] = false;
            sum[blocks] ++;
        }while(u != v);
        blocks ++;
    }
}
void solve()
{
    for(int i=1; i<=n; i++)
    {
        if( !low[i] )
            Tarjan(i);
    }
    for(int i=0; i<=n; i++)
    {
        int len = G[i].size(), v;
        for(int j=0; j<len; j++)
        {
            v = G[i][j];
            int a = belong[i], b = belong[v];
            if(a != b)
            {
                OutDegree[a] ++;
                 InDegree[b] ++;
            }
        }
    }
    LL x = INF, y;
    for(int i=0; i<blocks; i++)
    {
        if( !OutDegree[i] || !InDegree[i])
            x = Min(x, sum[i]);
    }
    y = n - x;
    LL ans = x*(x-1) + y*(y-1) + x*y - m;

    if(blocks == 1)
        printf("-1\n");
    else
        printf("%lld\n", ans);

}
int main()
{
    int T, cas = 1;
    scanf("%d", &T);

    while(T--)
    {
        scanf("%d %d",&n, &m);
        init();
        for(int i=0; i<m; i++)
        {
            int a, b;
            scanf("%d %d", &a, &b);
            G[a].push_back(b);
        }
        printf("Case %d: ", cas ++);
        solve();
    }
    return0;
}

 

posted @ 2015-08-10 17:59  向前走丶不回首  阅读(403)  评论(0编辑  收藏  举报