HDU 4635 Strongly connected

强连通分量+缩点+公式推导

缩点之后,记录一下每个缩点的真实点有几个,计算一个每个点的入度与出度,然后找出入度或出度为0,并且真实点个数最少的那个缩点,其余的点都可以随便连边了,这个缩点只能单向的向外界连边。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn = 100000 + 10;
int Dfn[maxn], U[100000 + 10], V[100000 + 10], Belong[maxn];
int In[maxn], Out[maxn], flag[maxn];
int SUM[maxn];
struct Point
{
    int id, dfn;
} point[maxn];
vector<int>G[maxn];
vector<int>FG[maxn];
int N, Tot;
int M, Block, in, out;

void init()
{
    for (int i = 0; i<maxn; i++) G[i].clear();
    for (int i = 0; i<maxn; i++) FG[i].clear();
    memset(Dfn, 0, sizeof Dfn);
    memset(In, 0, sizeof In);
    memset(Out, 0, sizeof Out);
    memset(flag, 0, sizeof flag);
    memset(SUM, 0, sizeof SUM);
    memset(Belong, 0, sizeof Belong);
    Tot = 0;//时间戳
    Block = 0;//强连通分量的数目
    in = 0;//统计入度为0的点的数目
    out = 0;//统计出度为0的点的数目
}

bool cmp(const Point&a, const Point&b)
{
    return a.dfn>b.dfn;
}

void Dfs(int now)
{
    flag[now] = 1;
    for (int i = 0; i<G[now].size(); i++)
    if (!flag[G[now][i]])
        Dfs(G[now][i]);
    Tot++;
    Dfn[now] = Tot;
}

void dfs(int now)
{
    Belong[now] = Block;
    for (int i = 0; i<FG[now].size(); i++)
    if (!Belong[FG[now][i]])
        dfs(FG[now][i]);
}

int main()
{
    int Case, cAse;
    scanf("%d", &cAse);
    for (Case = 1; Case <= cAse; Case++)
    {
        scanf("%d%d", &N, &M);
        init();
        for (int i = 1; i <= M; i++)
        {
            scanf("%d%d", &U[i], &V[i]);
            G[U[i]].push_back(V[i]);
            FG[V[i]].push_back(U[i]);
        }
        for (int i = 1; i <= N; i++) if (!flag[i]) Dfs(i);    
        for (int i = 0; i<N; i++)
            point[i].id = i + 1, point[i].dfn = Dfn[i + 1];    
        sort(point, point + N, cmp);
        for (int i = 0; i<N; i++)
        if (!Belong[point[i].id])
            Block++, dfs(point[i].id);
        for (int i = 1; i <= M; i++)
        if (Belong[U[i]] != Belong[V[i]])
            Out[Belong[U[i]]]++, In[Belong[V[i]]]++;
        for (int i = 1; i <= N; i++) SUM[Belong[i]]++;
        int St, MMA = 0x7FFFFFFF;
        for (int i = 1; i <= Block; i++)
        if ((!In[i] || !Out[i]) && (SUM[i]<MMA))
            MMA = SUM[i], St = i;
        int MK = 0;
        int ML = 0;
        for (int i = 1; i <= M; i++)
        {
            if (Belong[U[i]] == St && Belong[V[i]] == St) ML++;
            if (Belong[U[i]] == St || Belong[V[i]] == St) continue;
            MK++;
        }
        int Pri = (N - SUM[St])*(N - SUM[St] - 1) - MK + (N - SUM[St])*SUM[St] - max(In[St], Out[St]) + (SUM[St])*(SUM[St] - 1) - ML;
        printf("Case %d: ", Case);
        if (Block == 1) printf("-1\n");
        else printf("%d\n", Pri);
    }
    return 0;
}

 

posted @ 2015-08-29 11:26  Fighting_Heart  阅读(180)  评论(0编辑  收藏  举报